if ( ! window._ ){
	window._ = function( s ){ return s}
	}

var SITE_URL = [(location.protocol || 'http:'), '//', location.hostname].join('');

/* Common */
	function isset(val){
		return (val != undefined);
		}
	function valueInLimits(value, min, max){
		return Math.max(
			( max != undefined 
				? Math.min(value, max) 
				: value ),
			min);
		}


/* Platform detection */
var 
	BROWSER=(function(){
		var  
			ua = navigator.userAgent,
			webkit = /AppleWebKit/.test(ua), 
			safari = webkit && /Safari\//.test(ua);
		return {
			isIE: /*@cc_on!@*/false,
			isIE6:false /*@cc_on || @_jscript_version < 5.7 @*/ || 
				/msie 6/i.test(navigator.userAgent.toLowerCase()),
			isIE7:false /*@cc_on || @_jscript_version == 5.7 @*/ || 
				/msie 7/i.test(navigator.userAgent.toLowerCase()),
			isOpera:!!(window.opera && opera.version),
			isOpera95:!!((window.opera && opera.version) && window.scrollX==undefined),
			isFirefox:(ua.indexOf("Firefox") != -1),
			isGecko:!!(!document.attachEvent && document.addEventListener),
			isWebkit:webkit,
			isSafari: safari && /Version\//.test(ua),
			isChrome: safari && /Chrome\//.test(ua)
			}
		})(),
	OPERATING_SYSTEM=(function(){
		var res = {
			isLinux:navigator && navigator.platform && navigator.platform.search('Linux')>=0,
			isBsd:navigator && navigator.platform && navigator.platform.search(/Bsd/i)>=0
			};
		res.isUnix = (res.isLinux || res.isBsd);
		return res;
		})(),
	DEVICE = {
		isIpad: navigator.userAgent.match(/iPad/i) != null,
		isTouchDevice: (function(){
			var el = document.createElement('div');
			   el.setAttribute('ongesturestart', 'return;');
			   return (typeof el.ongesturestart == "function");
			})()
		};
		

/* Function inheritance */
	Function.prototype.inheritsFrom = function(superClass,proto) {
		var Inheritance = function(){};	
		Inheritance.prototype = superClass.prototype;	
		this.prototype = new Inheritance();	
		this.prototype.constructor = this;	
		this.superClass = superClass;
		this.prototype._parent=superClass.prototype;
		this.prototype._parentMethod=function(method){			
			var args = Array.prototype.slice.call(arguments);			
			if (is_function(this._parent[method])){
				var a=args.slice(1);
				return this._parent[method].call(this,a[0],a[1],a[2]);
				}
			}
		this.prototype._superMethod=function(method){
			if (typeof this._parent[method] == 'function'){
				return this._parent[method].apply(
					this, 
					Array.prototype.slice.call(arguments, 1)
					);
				}
			}
		if (is_object(proto)){
			$.extend(this.prototype, proto);
			}
		return this;
		}
		
/* Types */
	function is_function(func){
		return (func && typeof(func)=='function');
		}
	function is_object(o){
		return (typeof(o)=='object');
		}
	
	function is_array(o){		
		return (o!=null && typeof(o)=='object' && o.unshift!=undefined);
		}
	
	function is_string(o){
		return (typeof(o)=='string');
		}
	
	function is_numeric(o){
		return !isNaN(o);
		}
	function is_null(o){
		return o===null;
		}
	
	function is_date(o){
		return (o && typeof(o)=='object' && is_function(o.getTime));
		}
	function is_valid_date(o){
		return (is_date(o) && o.getDay && !isNaN(o.getDay()));
		}
		
	function method_exists(obj,m){
		return (obj && is_object(obj) && is_function((obj)[m]) );
		}
		

/* jQuery extensions */
if (window['jQuery']){
	
	/** 
	 * Simply form of jQuery.show for block elements
	 */
	jQuery.fn.showBlock = function(){
		for ( var i = 0, l = this.length; i < l; i++ ) {
			this[i].style.display = 'block';
			}
		return this;
		}
	/** 
	 * Simply form of jQuery.show for inline elements
	 */
	jQuery.fn.showInline = function(){
		for ( var i = 0, l = this.length; i < l; i++ ) {
			this[i].style.display = 'inline';
			}
		return this;
		}
	/** 
	 * Simply form of jQuery.show for inline block elements
	 */
	jQuery.fn.showInlineBlock = function(){
		for ( var i = 0, l = this.length; i < l; i++ ) {
			this[i].style.display = 'inline-block';
			if (BROWSER.isIE){
				this[i].style.zoom = 1;	
				this[i].style.display = 'inline';	
				}
			}
		return this;
		}
	/** 
	 * Simply form of jQuery.hide
	 */
	jQuery.fn.hideBlock = function(){
		for ( var i = 0, l = this.length; i < l; i++ ) {
			this[i].style.display = 'none';
			}
		return this;
		}
		
	jQuery.fn.searchInClass = function(prefix){
		if (this.length && this[0]){
			var parts=(this.attr('class')||'').split(' ');
			for (var i=0;i<parts.length;i++){
				var part=parts[i];				
				if (part.search(prefix)==0){
					return part.substr( prefix.length );
					}
				}
			}
		return undefined;
		};
	jQuery.fn.dataFromClass = function( prefix ){
		var 
			/** @type {Array} */
			parts,
			rx = new RegExp( '^' + trimStr( prefix , ' -' ) + '-(.+)$' ),
			m, mp, n, v,
			res = {};
		if ( this.length ){
			for (var i = 0, l = this.length; i < l; i++) {
				if ( this[ i ].className ){
					parts = this[ i ].className.split( ' ' );
					for (var j = 0, k = parts.length; j < k; j++) {
						m = String( parts[ j ] ).match( rx );
						if ( m && m[ 1 ] ){
							mp  = String( m[ 1 ] ).split( '-' );
							v = mp.pop();
							n = mp.join( '-' );
							if ( ! ( n in res ) ){
								res[ n ] = v;
								}
							}
						}
					}
				}
			}
		return res;
		}
	
	jQuery.fn.removeClassPrefixed = function( prefix ){
		var 
			/** 
			 * Parts of current class
			 * @type {Array} */
			_cl,
			/** 
			 * Parts of new class
			 * @type {Array} */
			_cln;
		if ( prefix ){
			for (var i = 0, l = this.length; i < l; i++) {
				_cl = this[ i ].className.split( ' ' );
				_cln = [];
				for (var j = 0, k = _cl.length; j < k; j++) {
					if ( _cl[ j ].indexOf( prefix ) ){
						_cln.push( _cl[ j ] );
						}
					}
				this[ i ].className = _cln.join( ' ' );
				}
			}
		return this;
		}		
		
	jQuery.fn.maxlength = function(ml){
		var 
			/** @type {jQuery} */
			$f = $(this),
			_val,
			_ml;
		for ( var i = 0, l = this.length; i < l; i++ ) {
			$f = $(this[i]);
			$f.bind('click keyup change', function(){
				_ml = ml == undefined 
					? parseInt($f.attr('maxlength'))
					: ml;
				_val = $f.val();
			    if(_val.length > _ml){
					$f.val(_val.substr(0, _ml));
					}
				});
			}
		return this;
		}

	jQuery.fn.center = function (){
		var
			$this = $( this ),
			$window = $( window );
		this.css( {
			position   : 'absolute',
			top        : Math.max( 0, (($window.height() - $this.outerHeight()) / 2) +
			                          $window.scrollTop() ) + 'px',
			left       : '50%',
			marginLeft : - $this.outerWidth() / 2
		} );
		return this;
	}

	jQuery.fn.serializeObject = function(){
	    var 
	    	o = {},
	    	a = this.serializeArray();
	    $.each(a, function() {
	        if (o[this.name] !== undefined) {
	            if (!o[this.name].push) {
	                o[this.name] = [o[this.name]];
	           		}
	            o[this.name].push(this.value || '');
	        	}
	        else {
	            o[this.name] = this.value || '';
	        	}
	   	 });
	    return o;
		};
	
	
	jQuery.eventDriven = function( obj ){
		var $obj = $( obj );
		obj.on = function(){
			$obj.on.apply( $obj, arguments );
			return obj;
			}
		obj.off = function(){
			$obj.off.apply( $obj, arguments );
			return obj;
			}
		return obj;
		}
	}
		

/* Form elements */
	function getRadioValue(el){
		var 
			res = null,
			iEl;
		el=$name(el);
		if (!el) {
			return "";
			}
		for (var i = 0, l = el.length; i < l; i++){
			iEl = el[i];
			if (iEl.checked) {
				res = iEl.value;
				break;					
				}
			}
		return res;
		}
	
	function getFileName (value){
		value = value.replace(/^\s|\s$/g, "");
		if (/\.\w+$/.test(value)){
			var m = value.match(/([^\/\\]+)\.(\w+)$/);
			if (m){
				return m[1] + '.' + m[2]
				}
			else {
				return "(file)"
				}
			}
		else{
			var m = value.match(/([^\/\\]+)$/);
			if (m){
				return m[1]
				}
			else{
				return "(file)"
				}
			}
		}
		
	/** 
	 * 
	 * @param {String} value
	 * @return {String}
	 */
	function getFileExt(value){
		return value 
			? trimStr(value).split('.').pop().toLowerCase()
			: '';
		}
	
	function selfBlur(){
		return this.blur();			
		}
	
		
/* XML */
	function parseLineXML(xml){
		if (!xml) {
			return false;
			}
		var res=[],
			fc = xml.firstChild,
			fcA = {}
		if (!fc) {
			return {};
			}
		if (fc.nodeType != 1) fc= fc.nextSibling;
		
		//Get fc attributes
		for (var a = 0, l = fc.attributes.length; a < l; a++){
			var attr = fc.attributes[a]
			if (attr.nodeType != 2) continue
			fcA[attr.nodeName] = attr.nodeValue
			}

 	 	for (var i = 0, l = fc.childNodes.length; i < l; i++){
			var node = fc.childNodes[i];
			if (node.nodeType != 1) continue
			
			res[i] = {
				value:node.firstChild
					? node.firstChild.data
					: "",
				data:{}};
			for (var a = 0, l = node.attributes.length; a < l; a++){
				var attr = node.attributes[a]
				if (attr.nodeType != 2) {
					continue;
					}
				res[i].data[attr.nodeName] = attr.nodeValue;
				}
			}
		return {
			head: fcA,
			body: res
			};
		}
		
		if (typeof DOMParser == "undefined") {
			   DOMParser = function () {return false;}
			
			   DOMParser.prototype.parseFromString = function (str, contentType) {
				  if (typeof ActiveXObject != "undefined") {
						 var d = new ActiveXObject("MSXML.DomDocument");
						 d.loadXML(str);
						 return d;
					  } else if (typeof XMLHttpRequest != "undefined") {
						 var req = new XMLHttpRequest;
						 req.open("GET", "data:" + (contentType || "application/xml") +
										 ";charset=utf-8," + encodeURIComponent(str), false);
						 if (req.overrideMimeType) {
							req.overrideMimeType(contentType);
							}
						 req.send(null);
						 return req.responseXML;
						}
					return false;
					}
			}
	
/* Caret position */
	function moveCaretToStart(inputObject){		
		if (inputObject.createTextRange){
			 //IE
			var r = inputObject.createTextRange();
			r.collapse(true);
			r.select();
			}
		else if (inputObject.selectionStart){
			// Mozilla/Gecko
			inputObject.setSelectionRange(0,0);
			inputObject.focus();
			}
		}
			
	function moveCaretToEnd(inputObject){			
		setCaretPosition(inputObject,$value(inputObject).length);
		}
	function getCaretPosition(ctrl) {
		ctrl=$id(ctrl)
		var CaretPos = 0;
		if (document.selection) {
			ctrl.focus();
			var Sel = document.selection.createRange();
			Sel.moveStart('character', - $value(ctrl).length);
			CaretPos = Sel.text.length;
			} 
		else if (ctrl.selectionStart || ctrl.selectionStart == '0')
			CaretPos = ctrl.selectionStart;
		return CaretPos;
		}

	function setCaretPosition(elem, caretPos) {
   		elem = $id(elem);
		if(elem != null) {
		    if(elem.createTextRange) {
		        var range = elem.createTextRange();
		        range.move('character', caretPos);
		        range.select();
		    }
		    else {
		        if(elem.selectionStart) {
		            elem.setSelectionRange(caretPos, caretPos);
                    elem.focus();
                    
                    // Trigger a "space" keypress.
                    triggerKeyPress(elem,0,32);
                    // Trigger a "backspace" keypress.
                    triggerKeyPress(elem,8,0);
		        	}
		        else{
		            elem.focus();
		        	}
		    	}
			}
		}
	function setSelection(elem, start, end) {
   		elem = $id(elem);
		if(elem != null) {
		    if(elem.createTextRange) {
		        var range = elem.createTextRange();
		        range.moveStart('character', start);
		        range.moveEnd('character', end);
		        range.select();
		    }
		    else {
		        if(elem.selectionStart) {
		            elem.setSelectionRange(start, end);
                    elem.focus();
                    
                    /* // Trigger a "space" keypress.
                    triggerKeyPress(elem,0,32);
                    // Trigger a "backspace" keypress.
                    triggerKeyPress(elem,8,0); */
		        	}
		        else{
		            elem.focus();
		        	}
		    	}
			}
		}
	function triggerKeyPress(elem,keyCode1,keyCode2){
		elem=$id(elem);
		var evt = document.createEvent("KeyboardEvent");
		if (typeof evt.initKeyboardEvent=='function'){
			evt.initKeyboardEvent("keypress", 
				true, true, null, false, false, false, false, keyCode1, keyCode2);
			}
		else{
			evt.initKeyEvent("keypress", 
				true, true, null, false, false, false, false, keyCode1, keyCode2);
			}
		elem.dispatchEvent(evt);
		}
		
	function getCaretPos(obj) {
		obj=$id(obj);
		obj.focus();
		if (obj.selectionStart)
			return obj.selectionStart;
		else if (document.selection) {
			return getCaretPosition(obj);
			}

		return 0;
		}
		
	function selectNode (node){
		node=$id(node);
		if (!node){
			return;
			}
		var selection, range, doc, win;
		if (
			(doc = node.ownerDocument) && 
			(win = doc.defaultView) && 
			typeof win.getSelection != 'undefined' && 
			typeof doc.createRange != 'undefined' && 
			(selection = window.getSelection()) && 
			typeof selection.removeAllRanges != 'undefined'
			){
			range = doc.createRange();
			range.selectNodeContents(node);
			selection.removeAllRanges();
			selection.addRange(range);
			}
		else if (
			document.body && 
			typeof document.body.createTextRange != 'undefined' && 
			(range = document.body.createTextRange())
			){
			range.moveToElementText(node);
			range.select();
			}
		}
	
	// event.type must be keypress
	function getChar( event ) {
		if (event.which == null) {  // IE
			if (event.keyCode < 32) return null; // спец. символ
			return String.fromCharCode(event.keyCode) 
			} 
	
		if (event.which!=0 && event.charCode!=0) { // все кроме IE
			if (event.which < 32) return null; // спец. символ
			return String.fromCharCode(event.which); // остальные
			} 
	
		return null; // спец. символ
		}


/* DOM */
	function $id(el){	
		var res;
		if (!el) {
			return false;
			}
		res = null;
		if (typeof(el) != "object"){
			if (document.getElementById(el)) {
				res = document.getElementById(el);
				}
			}
		else if(el.length!=undefined && el.slideDown != undefined){ 
			/* Checking if el is jquery object */
			res=el[0];
			}
		else{
			res=el
			}
		return res;
		}
	
	function $name(el){	
		if (!el) {
			return false;
			}
		var els = [];
	
		if (typeof(el) != "object"){
			els = document.getElementsByName(el);
			}
		
		if (els.length != 0) {
			return els;
			}
		else{
			return null;
			}
		}
	
	function $value(el,val){
		el = $id(el)
		if (!el) {
			return '';
			}
		if (isset(val)){			
			el.value = is_null(val) 
				? ''
				: val;
			}
		return el.value || '';		
		}
	
	function $displaying(el){
		return !!( (el = $id(el)) && el.offsetHeight);
		}
	
	function setChild(par, elID, elClass, elType, elContent, elParams){
		if (!par && !elID) {
			return false;
			}
		var el = $id(elID);
		
		if (par && !el && elType){
			//need to create and append new child
			par = $id(par);		
			el = document.createElement(elType);
			el = par.appendChild(el);
			if (elID) {
				el.id = elID;
				}
			}
		if (!el) {
			return false;
			}
		if (elClass) {
			el.className = elClass;
			}
		if (elContent){
			el.innerHTML = elContent;
			}
		if (elParams){
			el = concatObjects(el,elParams);
			}
		return el;
		}
		
	function unsetChild(el){		
		el = $id(el);
		if (el && el.parentNode){
			return el.parentNode.removeChild(el);
			}
		return false;
		}
		
	function searchInClass(el,base){
		el=$id(el);
		if (el && el.className){
			var parts=el.className.split(' ');
			for (var i=0;i<parts.length;i++){
				var part=parts[i];				
				if (part.search(base)==0){
					return part.substr(base.length);
					}
				}
			}
		return undefined;
		}
	
	function setChildExt(settings){
		var defaultSettings={
				parent:document.body,
				setType:'append',
				tag:'DIV',
				id:'',
				baseDocument:document
			};
		
		if (is_string(settings)){
			settings={className:settings};
			}
		settings=concatObjects(settings,defaultSettings);
		
		var el=$id(settings.id);
		if (el){
			return el;
			}	
		var par=$id(settings.parent);
		
		/* Fix IE 'name' attribute bug */
		if (settings.name && BROWSER.isIE){
			el=settings.baseDocument.createElement('<'+settings.tag+' name="'+settings.name+'">');
			}
		else{
			el=settings.baseDocument.createElement(settings.tag);
			if (settings.name){
				el.name=settings.name;
				}
			}
		
		if (!el) {
			return false;
			}
			
			
		if (settings.id){
			el.id=settings.id;
			}
		
		if (settings.type){
			el.type=settings.type;
			}
		if (isset(settings.value)){
			el.value=settings.value;
			}
		if (settings.className){
			el.className=settings.className;
			}
		if (settings.content){
			el.innerHTML=settings.content;
			}
		if (isset(settings.title)){
			el.title=settings.title;
			}
		if (settings.params && is_object(settings.params) ){
			for (var i in settings.params){				
				el[i]=settings.params[i];				
				}
			}
		if (settings.style && is_object(settings.style)){
			setStyle(el,settings.style);
			}
		if (settings.onclick && is_function(settings.onclick)){
			el.onclick=settings.onclick;
			}
		
		if (settings.onfocus && is_function(settings.onfocus)){			
			el.onfocus=settings.onfocus;
			}
		if (settings.onmouseover && is_function(settings.onmouseover)){
			el.onmouseover=settings.onmouseover;
			}
		if (settings.onmouseout && is_function(settings.onmouseout)){
			el.onmouseout=settings.onmouseout;
			}
		
		switch(settings.setType){
			case 'insertBefore':
				el=par.parentNode.insertBefore(el,par);
				break;
			case 'append':
				el=par.appendChild(el);
				break;
			}
		if (settings.child && is_object(settings.child)){
			setChildExt(
				concatObjects(
					settings.child,
					{
						parent:el
						}
					)
				);
			}
		
		if (settings.children && is_object(settings.children)){
			for (var i in settings.children){
				var child=settings.children[i];
				if (!is_object(child)){
					continue;
					}
				setChildExt(
					concatObjects(
						child,
						{
							parent:el
							}
						)
					);				
				}			
			}
		if (isset(settings.checked)){
			el.checked=settings.checked;
			}
		if (isset(settings.selected)){
			el.selected=settings.selected;
			}
		if (isset(settings.disabled)){
			el.disabled=settings.disabled;
			}
		
		if (settings.handlerFunction && is_function(settings.handlerFunction)){
			settings.handlerFunction(el);
			}
		
		return el;
		}
	
	function setChildren(el,children){
		el=$id(el);
		if (!el){
			el=document.body;
			}
		if (!is_object(children)){
			return false;
			}
		for (var i=0;i<children.length;i++){
			var cData=children[i];
			if (is_string(cData)){				
				cData={className:cData};				
				}
			el=setChildExt(
				rConcatObjects(cData,{parent:el})
				);
			}
		return el;
		}
		
	function setStyle(el,style){
		el=$id(el);
		if (!el || !style || !el.style || typeof style!='object'){
			return false;
			}
		var needPx=['top','left','width','height'];
		for (var property in style){
			var value=style[property];
			try{
				if (typeof value!='object' && typeof value!='function'){
					el.style[property]=value+( (in_array(needPx,property) && !isNaN(value) )?'px':'');					
					}
				}
			catch (e){
				document.writeln('error '+el+': '+property+'='+value);
				}
			}
		return true;
		}

/* Positioning and view */
		
	/** 
	 * Works like jQuery.offset 
	 * but in addition to left & top it returns right & bottom
	 * @param {} block
	 * @return {Object}
	 */
	function $where(block){
		var 
			theBlock = $id(block),
			blockLeft = 0,
			blockTop = 0;
		if (!theBlock){
			return false;
			}
		while(block) {
			blockLeft += block.offsetLeft;
			blockTop += block.offsetTop;
			block = block.offsetParent;
			}
		return {
			left:	blockLeft, 
			top:	blockTop,
			right:	blockLeft+theBlock.offsetWidth,
			bottom:	blockTop+theBlock.offsetHeight
			};
		}
		/* Alias for $where */
		function getWhereIs(block){
			return $where(block);
			}
		
	function getWhereIsEvent(e){
		if (e.pageX){		
			return {left:e.pageX, top:e.pageY};
			}
		return {
			left:e.clientX + document.body.parentElement.scrollLeft,
			top:e.clientY + document.body.parentElement.scrollTop
			};
		}
	
	function placeUnderCursor (el, x, y){
		el=$id(el);
		if (!el){
			return false;
			}
		el.style.position = 'absolute';
		el.style.left = (x - el.offsetWidth + 10) + 'px';
		el.style.top = (y - 5) + 'px';
		}	
	
	function setPosition(el,pos){
		el=$id(el)
		if (!el) {
			return false;
			}
		
		if (pos.left!=null) el.style.left=pos.left+"px"
		if (pos.top!=null) el.style.top=pos.top+"px"
		
		return false
		}	
	
	function putInScreenCenter(el,setX,offsetTop,offsetLeft){	
		el=$id(el);
		if (!el){
			return false;
			}
		el.style.position='absolute';
		var winH = (window.opera)? window.innerHeight:document.documentElement.clientHeight,
			winY = (document.all)?document.documentElement.scrollTop:window.pageYOffset,			
			elY = Math.max(0,Math.round(winY+winH/2-el.clientHeight/2)+(offsetTop||0)),
			winW = document.documentElement.offsetWidth,
			elX = setX !== false ? Math.round(winW / 2 - el.offsetWidth / 2) : null;
			if (document.all) {
				elY-=30;
				}
		setPosition(el,{left:elX,top:elY});
		}
	
	/** 
	 * Switces new class from given states array per each time
	 * @param {} el
	 * @param {Boolean} state
	 * @param {Array} states
	 * @return {Boolean}
	 */
	function toggleClass(el, state, states){
		states = states
			? states
			: ['hidden','showed'];
		el=$id(el);
		if (!el){
			return false;
			}
		var searchTmpl='/'+states[0]+'/',
			newState=(state==null)?((el.className.search(states[0])>-1)?1:0):state,
			currState=(newState==0)?1:0;
		if (el.className!=null && el.className.search(states[currState])>-1){
			el.className=el.className.replace(states[currState], states[newState]);
			}
		else {
			if (el.className!=null && el.className.search(states[newState])<0){
				el.className+=" "+states[newState];
				}
			}
		return newState;
		}	
	
	function getScrollBarWidth () {
		var 
			inner = document.createElement('p'),
			w1, w2;
		inner.style.width = "100%";
		inner.style.height = "200px";
		
		var outer = document.createElement('div');
		outer.style.position = "absolute";
		outer.style.top = "0px";
		outer.style.left = "0px";
		outer.style.visibility = "hidden";
		outer.style.width = "200px";
		outer.style.height = "150px";
		outer.style.overflow = "hidden";
		outer.appendChild (inner);
		
		document.body.appendChild (outer);
		w1 = inner.offsetWidth;
		outer.style.overflow = 'scroll';
		w2 = inner.offsetWidth;
		if (w1 == w2) {
			w2 = outer.clientWidth;
			}
		document.body.removeChild (outer);
		return (w1 - w2);
		};
	
		
/* Dragging */
		
	/** 
	 * Allows drag-n-drop
	 * @type {Function} 
	 */	
	var $drag;
	(function(){
		var DraggingItem = {};
		function startDrag (event, _this, _targetBlock, settings){
			DraggingItem.This = $id(_this);
			DraggingItem.Target = $id(_targetBlock);		
			if (!DraggingItem.This || !DraggingItem.Target){
				throw new Error('error dragging '+DraggingItem.Target);
				return false;
				}
			DraggingItem.TargetXY=getWhereIs(DraggingItem.Target);
			
			var defaultSettings={
				minLeft:1,
				minTop:1
				};
			DraggingItem.settings=concatObjects(settings,defaultSettings);
			if (DraggingItem.settings.onbegin) {
				DraggingItem.settings.onbegin(DraggingItem.Target);
				}
			if (isset(DraggingItem.settings.maxXDelta)){
				var startTargetLeft=Number(DraggingItem.Target.style.left.slice(0,-2));
				if (!isNaN(startTargetLeft)){
					DraggingItem.settings.minLeft=startTargetLeft-DraggingItem.settings.maxXDelta;
					DraggingItem.settings.maxLeft=startTargetLeft+DraggingItem.settings.maxXDelta;
					}
				else{
					DraggingItem.settings.minLeft=DraggingItem.TargetXY.left-DraggingItem.settings.maxXDelta;
					DraggingItem.settings.maxLeft=DraggingItem.TargetXY.left+DraggingItem.settings.maxXDelta;
					}
				}
			if (isset(DraggingItem.settings.maxYDelta)){
				var startTargetTop=Number(DraggingItem.Target.style.top.slice(0,-2));
				if (!isNaN(startTargetTop)){
					DraggingItem.settings.minTop=startTargetTop-DraggingItem.settings.maxYDelta;
					DraggingItem.settings.maxTop=startTargetTop+DraggingItem.settings.maxYDelta;
					}
				else{
					DraggingItem.settings.minTop=DraggingItem.TargetXY.top-DraggingItem.settings.maxYDelta;
					DraggingItem.settings.maxTop=DraggingItem.TargetXY.left+DraggingItem.settings.maxYDelta;
					}
				}
		
			var position = new Object();
			if (BROWSER.isIE || BROWSER.isOpera95){			
				position.x = window.event.clientX + document.documentElement.scrollLeft + document.body.scrollLeft;
				position.y = window.event.clientY + document.documentElement.scrollTop + document.body.scrollTop;
				}
			else if (BROWSER.isGecko || BROWSER.isOpera){			
				position.x = event.clientX + window.scrollX;
				position.y = event.clientY + window.scrollY;
				}
		
			DraggingItem.cursorStartX = position.x;
			DraggingItem.cursorStartY = position.y;
			DraggingItem.Target.style.position = 'absolute';
			
			DraggingItem.StartLeft = parseInt (DraggingItem.Target.style.left);
			DraggingItem.StartTop = parseInt (DraggingItem.Target.style.top);
		
			
			if (isNaN (DraggingItem.StartLeft)) {DraggingItem.StartLeft = DraggingItem.TargetXY.left }
			if (isNaN (DraggingItem.StartTop)) DraggingItem.StartTop = DraggingItem.TargetXY.top;
			if (BROWSER.isIE){
				document.attachEvent ("onmousemove", ProceedDrag);
				document.attachEvent ("onmouseup", StopDrag);
				window.event.cancelBubble = true;
				window.event.returnValue = false;
				}
			else if (BROWSER.isGecko || BROWSER.isOpera){
				document.addEventListener ("mousemove", ProceedDrag, true);
				document.addEventListener ("mouseup", StopDrag, true);
				event.preventDefault();
				}
			}
			
		function ProceedDrag (event){
			var 
				nextX, nextY,
				x, y;
			if (BROWSER.isIE || BROWSER.isOpera95) {
				x = window.event.clientX + document.documentElement.scrollLeft + document.body.scrollLeft;
				y = window.event.clientY + document.documentElement.scrollTop + document.body.scrollTop;
				}
			else if (BROWSER.isGecko || BROWSER.isOpera){	
				x = event.clientX + window.scrollX;
				y = event.clientY + window.scrollY;
				}	
		
			nextX = DraggingItem.StartLeft + x - DraggingItem.cursorStartX;
			nextX = valueInLimits(nextX, DraggingItem.settings.minLeft, DraggingItem.settings.maxLeft);
			
			DraggingItem.Target.style.left = nextX + 'px';
		
			nextY = DraggingItem.StartTop  + y - DraggingItem.cursorStartY;
			nextY = valueInLimits(nextY, DraggingItem.settings.minTop, DraggingItem.settings.maxTop);
			
			DraggingItem.Target.style.top = nextY + 'px';
		
			if (BROWSER.isIE){
				window.event.cancelBubble = true;
				window.event.returnValue = false;
				}
			if (BROWSER.isGecko || BROWSER.isOpera95) {
				event.preventDefault();
				}
			
			if (DraggingItem.settings.onmove/*  && is_function(DraggingItem.settings.onmove) */) {
				DraggingItem.settings.onmove(DraggingItem.Target,nextX,nextY);
				}
			}
		
		function StopDrag (event){
			if (BROWSER.isIE){
				document.detachEvent ("onmousemove", ProceedDrag);
				document.detachEvent ("onmouseup", StopDrag);
				}
			if (BROWSER.isGecko || BROWSER.isOpera){
				document.removeEventListener ("mousemove", ProceedDrag, true);
				document.removeEventListener ("mouseup", StopDrag, true);
				}
		
			if (DraggingItem.settings.oncomplete && is_function(DraggingItem.settings.oncomplete)) {
				DraggingItem.settings.oncomplete(DraggingItem.Target);
				}
			}
		/*Public alias for startDrag*/
			$drag = function(event, _this, _targetBlock, settings){
				startDrag(event, _this, _targetBlock, settings);
				}
				
		/* jQuery drag-n-drop plugin */
			if (window['jQuery']){
				(function($){
					var 
						trackAreaClass = 'dragging-over',
						trackAreaOffsetDataKey = '_dragTrackingOffset',
						/** 
						 * Checks if given areas under draging elem 
						 * placed in [left,top] point
						 */
						trackArea = function(/* Object */ta, left, top ){
							var 
								res,
								length = ta.area ? ta.area.length : 0;
							ta.area && $.each(ta.area, function( num ){
								var
									$a = $(this),
									offset = $a.data(trackAreaOffsetDataKey) || $a.offset(),
									targetOffset = {
										left:		0,
										top:		0,
										leftFactor: 0,
										topFactor:	0
										},
									_res = (
										left 	>= offset.left && 
										top 	>= offset.top &&
										left 	<= (offset.right || (offset.right = offset.left + $a.outerWidth())) &&
										top 	<= (offset.bottom || (offset.bottom = offset.top + $a.outerHeight()))
										);
								if (_res){
									targetOffset = {
										left:		left - offset.left,
										top:		top - offset.top
										};
									targetOffset.leftFactor = targetOffset.left / (offset.right - offset.left);
									targetOffset.topFactor = targetOffset.top / (offset.bottom - offset.top);
									}
//								$a.data(trackAreaOffsetDataKey, offset);
								$a.toggleClass(trackAreaClass, _res);
								if (res !== false){
									/* Total result is true only if all areas is under draging object */
									res = _res;
									}
								ta.handler && ta.handler($a, _res, targetOffset, { 
										num 	: num,
										first 	: num == 0,
										last	: num == length - 1,
										offset  : offset
										} );
								});
							return res;
							},
						/** 
						 * Deletes cached data used when tracked areas while dragging
						 * Also delete over-dragging class from areas
						 */
						clearTrackAreaCache = function(ta){
							ta.area && $.each(ta.area, function(){
								$(this)
									.data(trackAreaOffsetDataKey, null)
									.removeClass(trackAreaClass);
								})	
							};
					$.fn.allowDrag = function(/* Object */_data){
						var
							data = {
								useClone:	false,
								trackAreas: []
								},
							/** @type {jQuery} */
							$target,
							/** @type {jQuery} */
							$clone,
							/** @type {jQuery} */
							$dragger,
							/** @type {String} */
							draggerPath,
							/** @type {Function} */
							_clientMove,
							/** @type {Function} */
							_clientComplete,
							/** @type {Object} */
							_completeData,
							
							targetWidth,
							targetHeight,
							targetRight,
							targetBottom,
							
							/** 
							 * Areas for placing on tracking 
							 * Array for inner using
							 * @type {Object{}}
							 */
							trackAreas = [],
							/** @type {jQuery} */
							_trAr,
							obj = {
								setTrackAreas: function(areas, append){
									!append && (trackAreas = []);
									for (var i = 0, l = areas.length; i < l; i++) {
										if ($.isFunction(areas[i])){
											trackAreas.push({
												area: 		_trAr,
												handler:	areas[i]
												});
											_trAr = undefined;
											}
										else{
											if (!_trAr){
												_trAr = $(areas[i]);
												}
											else{
												_trAr = _trAr.add($(areas[i]));
												}
											}
										}
									if (_trAr){
										trackAreas.push({
											area: 		_trAr
											});
										}
									}
								};
//						this.data('_dragControl', obj);
						
						_data && $.extend(data, _data);
						
						/* Transform tracking areas to required inner form */
						if (data.trackAreas.length){
							obj.setTrackAreas(data.trackAreas);
							}
						if (typeof(data.dragger) == 'object'){
							$dragger = $(data.dragger);
							}
						else if (typeof(data.dragger) == 'string'){
							draggerPath = data.dragger;
							}
						
						/* Using $element.data is too slow */
						$.data(this, '_dragControl', obj);
						
						for (var i = 0, l = this.length; i < l; i++) {
							$target = $(this[i]);
							if (draggerPath){
								$dragger = $(draggerPath, $target);
								}
							else{
								$dragger = is_object(data.dragger) ? $(data.dragger): $target;
								}
							$dragger.css({
								cursor: 'move'});
							if (data.useClone){
								_clientComplete = data.oncomplete;
								_clientMove = data.onmove;
								$dragger.mousedown(function(/* Event */e){
									targetWidth = $target.width();
									targetHeight = $target.height();
									$clone = $target.clone()
										.addClass('dragging-clone')				
										.css({
											position:	'absolute',
											zIndex:		10010
											})
										.css($target.offset())
										.width(targetWidth)
										.height(targetHeight)
										.appendTo(document.body);
									data.oncomplete = function(){
										$(document.body).removeClass('dragging-process');
										_completeData = $clone.offset();
										$clone.remove();
										_clientComplete && _clientComplete($target, _completeData);
										if (trackAreas.length){
											for (var i = 0, l = trackAreas.length; i < l; i++) {
												clearTrackAreaCache(trackAreas[i]);
												}
											}
										}
									data.onmove = function(target, left, top){
//										console.time('onmove');
										targetRight = left + targetWidth;
										targetBottom = top + targetHeight;
										if (trackAreas.length){
											
											for (var i = 0, l = trackAreas.length; i < l; i++) {
												trackArea(
													trackAreas[i], 
													(left + targetRight) * 0.5, 
													(top + targetBottom) * 0.5													);
												}
											}
										_clientMove && _clientMove.apply(this, arguments);
//										console.timeEnd('onmove');
										}
									$(document.body).addClass('dragging-process');
									startDrag(e, $target, $clone, data);
									});
								}
							else{
								$target.mousedown(function(/* Event */e){
									startDrag(e, $dragger || $target, $target, data);
									});
								}
							}
						return this;
						};
					})(jQuery);
				}
		})();
	
	
/* Arrays */
	function in_array(arr,el){
		var res=0
		for (var n in arr){
			if (el==arr[n]) {
				res++;
				}
			}
		return res;
		}
	
	function setArray(el){
		if (is_array(el)){
			return el;
			}
		else {
			var a=[];
			isset(el) && a.push(el);
			return a;
			}
		}
	function array_rearrange(arr,ind1,ind2){
		var c = arr[ind1];
		arr.splice(ind1, 1);
		arr.splice(ind2, 0, c);
		return arr;
		}
	
	function array_rand(arr){
		var l=arr.length;
		var ind=( Math.round (Math.random()*(l-1)) ).between(0,l-1);
		return arr[ind];
		}
/* Objects */
	
	/** 
	 * Handler for get / set operation with inner storage
	 */
	function storage(storage, data, value){
		if (data != undefined){
			if (typeof data == 'object'){
				/* Extending data by given object */
				$.extend(storage, data);
				}
			else if (value == undefined){
				/* Returning data value by given key */
				return storage[data];
				}
			else{
				/* Seting data value by given key  */
				storage[data] = value;
				}
			}
		/* If nothing given returning all storage hash */
		return storage;
		};		
		
	/** 
	 * Returns property of object by its name
	 * Supporting incrementally names like 'path.to.inner.prop'
	 * @param {Object} obj
	 * @param {String} prop
	 * @return {}
	 */
	function _prop(obj, prop){
		
		if (obj && prop && (prop in obj)){
			/* Fast return for simple prop */
			return obj[prop];
			}
		var 
			parts = prop.split('.'),
			res;
		if (!obj || !prop){
			return undefined;
			}
		if (parts.length){
			res = obj;
			for(var i = 0, l = parts.length; i < l; i++){
				if (res == undefined){
					return undefined;
					}
				res = res[parts[i]];
				}
			return res;
			}
		else{
			return obj[prop];
			}
		}
		
	function concatObjects(obj1,obj2,isRecursive){
		var res={};
		for (var pName in obj1){
			res[pName]=obj1[pName];
			}
		for (var pName in obj2){
			if (isRecursive && is_object(obj2[pName]) && is_object(res[pName])){
				res[pName]=concatObjects(res[pName],obj2[pName]);
				}
			else if (!isset(res[pName])){
				res[pName]=obj2[pName];
				}
			}
		return res;
		}
		
	/* alias for recursive case of concatObjects */
	function rConcatObjects(obj1,obj2){
		return concatObjects(obj1,obj2,'recursive');
		}
		
	function duplicateObject(obj){
		if (is_date(obj)){
			return obj;
			}
		var res = is_array(obj) ? [] : {};
		for (var i in obj){
			if (is_object(obj[i])){
				res[i] = duplicateObject(obj[i]);
				}
			else{
				res[i] = obj[i];
				}			
			}
		return res;
		}
		
	function removeFromObject(obj, key){
		var _obj={};
		for (var i in obj){
			if (i != key){
				_obj[i] = obj[i];
				}
			}
		return _obj;
		}
	
/* Debug */	
	function testObject(obj,isWrite,noAlert,level){
		var o="",
			sprt=isWrite?"<br/>":"\n";
		if (!level){
			level=0;
			}
		var spacer='';	
		var maxIterations=256;
		for (var i=0;i<level;i++){
			spacer+='  ';
			}
		if (level>256){
			return '..too much iterations';
			}
		if (is_object(obj)){
			var num=0;
			for (var p in obj){
				if (++num>maxIterations){
					return '..too much iterations';
					}
				var subObj=obj[p];
				var type=typeof(subObj);
				if (subObj==null){
					type='Null'
					}
				else if (subObj.pop){
					type='Array';
					}
				else if (subObj.charAt || subObj==''){
					type='String';	
					}
				else if (!isNaN(Number(subObj))){
					type='Number';	
					}
				if (is_function(subObj)){
					continue
					}
				o+=sprt+spacer+p+'['+type+']: ';				
				if (is_object(subObj)){
					o+=testObject(subObj,false,true,level+1)
					}
				else{
					o+=subObj;
					}
				}
			}
		else{
			o+=spacer+obj;
			}
		if (isWrite){
			document.write('<pre>'+o+'</pre>')
			}
		else {
			if (!noAlert)
				alert (o)
			}
		return o;
		}
		
	function dumpObject(obj,isWrite,noAlert){
		var o="",
			sprt=isWrite?"<br/>":"\n"
		for (var p in obj){
			var subObj=obj[p];
			o+=p+"=>"+subObj+sprt
			}
		if (isWrite){
			document.write(o)
			}
		else {
			if (!noAlert)
				alert (o)
			}
		return o;
		}
	

	function getKeyPressed(e){
		var KEYCODES=new Array()
			KEYCODES[9]="TAB"
			KEYCODES[13]="ENTER"
			KEYCODES[27]="ESC"
			KEYCODES[35]="END"
			KEYCODES[36]="HOME"
			KEYCODES[37]="ARROWLEFT"
			KEYCODES[38]="ARROWUP"
			KEYCODES[39]="ARROWRIGHT"
			KEYCODES[40]="ARROWDOWN"			
			
		var intKey=-1,
			targetField
		if (window.event){
			intKey=event.keyCode
			targetField=event.srcElement
			}
		else{
			intKey=e.which
			targetField=e.target
			}

		var res=(KEYCODES[intKey])?KEYCODES[intKey]:intKey
		return res
		}
	
		
/* Block screen */
	function blockScreen(className){
		if ($id('blockscreen')){
			return false;
			}
		var bs=setChildExt({id:'blockscreen',className:className||''});
		resizeBlockScreen();
		}
	function unblockScreen(){
		if (!$id('blockscreen')) {
			return false;
			}
		unsetChild('blockscreen');
		}
	function resizeBlockScreen(){		
		var bs=$id('blockscreen');
		if (!bs){				
			return false;
			}
		var bodyWrapHeight=$id('body-wrap')?$id('body-wrap').clientHeight:0;
		var sizes={
			height:Math.max(
				document.documentElement.clientHeight,
				document.body.clientHeight,bodyWrapHeight
				),
			width:Math.max(
				document.documentElement.clientWidth,
				document.body.clientWidth
				)
			};
		setStyle(bs, sizes);
		return true;
		}
	if (window['jQuery']){
		jQuery(window).resize(resizeBlockScreen);
		}
	
/* Images */
	function getImgSize( src, onready ){
		var 
			size = { width : 0 , height : 0 },
			img = new Image();
		img.onload = function(){
			size.width = this.width;
			size.height = this.height;
			$.isFunction(onready) && onready( size );
			return;
			}
		img.src=src;
		}
		
/* Flash */
	function paramString(params,escaping){
		if (typeof params != 'object'){
			return params;
			}
		var paramsStr = [];
		for (var paramName in params){
			paramsStr.push(paramName + '=' + 
				(escaping
					? encodeURIComponent(params[paramName])
					: params[paramName])
				)
			}
		return paramsStr.join('&amp;');
		}
	function parseParamString(str){
		var params={};
		var parts=str.split('?').pop().split('&');
		for(var i=0; i<parts.length; i++){
			var part=parts[i].split('=');
			params[part[0]]=part[1];
			}
		return params;
		}
	function buildFlashExt(settings){
		var 
			defaultSettings={
				version:	7,
				width:		'100%',
				height:		'100%',
				name:		'flashmovie',
				wmode:		'transparent',
				isWrite:	false
				},
			flashvars,
			html;
		settings = concatObjects(settings,defaultSettings);
		flashvars = settings.params 
			? paramString(settings.params,true)
			: '';
		if (!FLASH_CHECKING.DetectFlashVer(settings.version)){
			if ( typeof settings.noFlash == 'function'){			
				settings.noFlash();
				}
			else if (settings.noFlash != undefined){
				html = settings.noFlash.toString();
				}
			}
		else{
			html =
				BROWSER.isIE
				?	[
					'<', 'object ' , 
						'classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" ' , 
						'width="',  settings.width,  '" ' , 
						'height="', settings.height, '" ' , 
						'id="', settings.name, '">' , 
						'<', 'param name="movie" value="', settings.src, '">' , 
						'<', 'param name="wmode" value="', settings.wmode, '" />' , 
						'<', 'param name="quality" value="high">' , 
						'<', 'param name="allowScriptAccess" value="always" />' , 
						'<param name="menu" value="false" />' , 
						'<param name="FlashVars" value="', flashvars, '" />' , 
					'<', '/object>'].join('')
				: ['<', 'embed ' , 
					'src="', settings.src, '" ',  
					'quality="high" ',  
					'wmode="', settings.wmode, '" ', 
					'width="',settings.width,'" ', 
					'height="',settings.height,'" ', 
					'name="',settings.name,'"  ', 
					'id="',settings.name,'" ', 
					'menu="false" ', 
					'allowscriptaccess="always" ', 
					'type="application/x-shockwave-flash" ', 
					'flashvars="',flashvars,'"/>'].join('');
			}
		settings.isWrite && document.write(html);
		return html;	
		}
		
		/**
		 * Generates flash html
		 * Alias for buildFlashExt
		 * @param {Object} settings
		 */
		function $flash(settings){
			return buildFlashExt(settings);
			}
	/**
	 * Returns link to flash object
	 */
	function $flashMovie(name){
		return BROWSER.isIE ? window[name] : document.getElementById(name);
		}
		
/**
 * Provides information about actual flash plugin params
 */
var FLASH_CHECKING={
	isIE:(navigator.appVersion.indexOf("MSIE") != -1) ? true : false,
	isWin:(navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false,
	isOpera:(navigator.userAgent.indexOf("Opera") != -1) ? true : false,
	ControlVersion:function(){
		var version;
		var axo;
		var e;
	
		// NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry
	
		try {
			// version will be set for 7.X or greater players
			axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
			version = axo.GetVariable("$version");
		} catch (e) {
		}
	
		if (!version)
		{
			try {
				// version will be set for 6.X players only
				axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");
				
				// installed player is some revision of 6.0
				// GetVariable("$version") crashes for versions 6.0.22 through 6.0.29,
				// so we have to be careful. 
				
				// default to the first public version
				version = "WIN 6,0,21,0";
	
				// throws if AllowScripAccess does not exist (introduced in 6.0r47)		
				axo.AllowScriptAccess = "always";
	
				// safe to call for 6.0r47 or greater
				version = axo.GetVariable("$version");
	
			} catch (e) {
			}
		}
	
		if (!version)
		{
			try {
				// version will be set for 4.X or 5.X player
				axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3");
				version = axo.GetVariable("$version");
			} catch (e) {
			}
		}
	
		if (!version)
		{
			try {
				// version will be set for 3.X player
				axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3");
				version = "WIN 3,0,18,0";
			} catch (e) {
			}
		}
	
		if (!version)
		{
			try {
				// version will be set for 2.X player
				axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
				version = "WIN 2,0,0,11";
			} catch (e) {
				version = -1;
			}
		}
		
		return version;
		},
	GetSwfVer:function(){
			// NS/Opera version >= 3 check for Flash plugin in plugin array
			var flashVer = -1;
			
			if (navigator.plugins != null && navigator.plugins.length > 0) {
				if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) {
					var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : "";
					var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description;
					var descArray = flashDescription.split(" ");
					var tempArrayMajor = descArray[2].split(".");			
					var versionMajor = tempArrayMajor[0];
					var versionMinor = tempArrayMajor[1];
					var versionRevision = descArray[3];
					if (versionRevision == "") {
						versionRevision = descArray[4];
					}
					if (versionRevision[0] == "d") {
						versionRevision = versionRevision.substring(1);
					} else if (versionRevision[0] == "r") {
						versionRevision = versionRevision.substring(1);
						if (versionRevision.indexOf("d") > 0) {
							versionRevision = versionRevision.substring(0, versionRevision.indexOf("d"));
						}
					}
					var flashVer = versionMajor + "." + versionMinor + "." + versionRevision;
				}
			}
			// MSN/WebTV 2.6 supports Flash 4
			else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4;
			// WebTV 2.5 supports Flash 3
			else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3;
			// older WebTV supports Flash 2
			else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2;
			else if ( this.isIE && this.isWin && !this.isOpera ) {
				flashVer = this.ControlVersion();
			}	
			return flashVer;
		},
	 DetectFlashVer:function(reqMajorVer, reqMinorVer, reqRevision){
			versionStr = this.GetSwfVer();
			if (versionStr == -1 ) {
				return false;
			} else if (versionStr != 0) {
				if(this.isIE && this.isWin && !this.isOpera) {
					// Given "WIN 2,0,0,11"
					tempArray         = versionStr.split(" "); 	// ["WIN", "2,0,0,11"]
					tempString        = tempArray[1];			// "2,0,0,11"
					versionArray      = tempString.split(",");	// ['2', '0', '0', '11']
				} else {
					versionArray      = versionStr.split(".");
				}
				var versionMajor      = versionArray[0];
				var versionMinor      = versionArray[1];
				var versionRevision   = versionArray[2];
		
					// is the major.revision >= requested major.revision AND the minor version >= requested minor


				if (versionMajor >= parseFloat(reqMajorVer)) {
					return true;
				} else if (versionMajor == parseFloat(reqMajorVer)) {
					if (versionMinor > parseFloat(reqMinorVer))
						return true;
					else if (versionMinor == parseFloat(reqMinorVer)) {
						if (versionRevision >= parseFloat(reqRevision))
							return true;
					}
				}
				return false;
			}
		}
	}
	
/* Popup */
	function popUp (settings){
		var defaultSettings={
			url:'',
			width:350,
			height:600,
			top:200,
			left:200,
			menubar:'no',
			directories:'no',
			location:'no',
			resizable:'yes',
			scrollbars:'no',
			toolbar:'no'
			};
		settings=concatObjects(settings,defaultSettings);
		
		if (settings.width){
			settings.width+=20;
			}
		if (settings.height){
			settings.height+=20;
			}
		if (settings.content){
			settings.url='';
			}
		POPUP_WIN = window.open(
			settings.url,
			'POPUP_WINDOW',
			(function(){
				var a=[];
				for (var i in settings){
					if (i!='url' && settings[i]){
						a.push(i+'='+settings[i])
						}
					}
				return a.join(', ');
				})()
			);
		if (settings.content){
			if (!POPUP_WIN.document.body) {
				settings.content='<body>'+settings.content+'</body>';
				}
			POPUP_WIN.document.open()
			POPUP_WIN.document.write(
				'<head><title>'+(settings.title||'')+'</title>'
				+'<style type="text/css">A{cursor:pointer;}</style>'
				+'</head>'
				+settings.content
				);
			POPUP_WIN.document.title=(settings.title||'');
			POPUP_WIN.document.close();
			}
		return false;
		}



/* Strings */
		/** 
		 * Parses simple templates
		 * @param {String} tmpl
		 * @param {Object} ns
		 * @param {Object} actions
		 * @return {String}
		 */
		function _tmpl(tmpl, ns, actions) {
			if (!tmpl){
				return '';
				}
			var fn = function(w, g) {
				g = g.split("|");
				var cnt = _prop(ns,g[0]);
				for (var i = 1, l = g.length; i < l; i++){						
					cnt = eval(g[i])(cnt);
					}
				return isset(cnt)?cnt:'';
				};
			return tmpl.replace(/\%\(([A-Za-z0-9_|.]+)\)/g, fn);
			}
	
	function j(){
		if ( arguments.length ){
			return Array.prototype.join.call( arguments , '' );
			}
		return '';
		}
		
	var h = j // Alias for backward compatibility
			
	function trimStr(str, charlist) {
		if ( ! str ){
			return '';
			}
		charlist = !charlist 
			? ' \\s\\xA0' 
			: charlist.replace(/([\[\]\(\)\.\?\/\*\{\}\+\$\^\:])/g, '\$1');
		return str.replace(
			new RegExp('^[' + charlist + ']+|['+charlist+']+$', 'g'), 
			'');
		}
			
	function NtoBR( str ){
		return str ? str.replace( /\r?\n/g , '<br/>' ) : '';
		}	
	
	function BRtoN( str ){
		return str ? str.toString().replace( new RegExp('<br\s*\/?>', 'ig') , "\r\n" ) : '';
		}
	
	function str_quote(s,q){		
		return s?(q||"'")+s+(q||"'"):'';
		}
	
	function str_repeat( input , multiplier ){
		return new Array( multiplier + 1 ).join( input );
		}	
		
	function wrapBreakWord(r,step){
		if (!step){
			step=15;			
			}
		if (BROWSER.isIE){
			/*For IE its better to use white-space:break-word; on parent container */
			return r;
			}		
		r=r.replace(new RegExp("(.{"+step+"})","ig"),"<span class=\"wrap-quantum\">$1</span>");
		return r;
		}
		
	function parseTemplate(tmpl,data){
		var reg=new RegExp(/\{\%\w+\%\}/);		
		var iter=0;
		while(tmpl.search(reg)>0 && ++iter<10){
			var start=tmpl.search(reg)+2;									
			var end=start;			
			var symb;
			var key='';
			do{
				key+=tmpl.charAt(end++);
				}			
			while(tmpl.charAt(end)!='%' && tmpl.charAt(end+1)!='}' && end<(tmpl.length-1));
			
			tmpl=tmpl.substr(0,start-2)+(data[key]||'')+tmpl.substr(end+2);
			}
		return tmpl
		}
	
	function getDomainName(d){
		if (!d) {
			return '';
			}
		if (d.search(/http:\/\//i)==0){
			d=d.slice(7);
			}
		else if (d.search(/https:\/\//i)==0){
			d=d.slice(8);
			}
		if (d.search(/www\./i)==0){
			d=d.slice(4);
			}
		if (d.substr(-1)=='index.html'){
			d=d.slice(0,-1);
			}
		return d;
		}
		
	function getHost(d){
		var 
			p0,
			p,
			schema;
		if (d){
			p0 = d.toString().split('://');
			return p0.shift() + '://' + p0.join('://').split('index.html').shift();
			}
		}
		
	function removeUrlSchema(d){
		return d?d.replace(/^(?:https?:\/\/)/i,""):'';
		}
		
	function isClickableUrl(url){
		return !!/^https?:\/\/|ftp:\/\//i.test(url);
		}	
		
	function makeUrl(u){
		return (/https?:\/\//i.test(u)?'':'http://')+u;
		}
		
	function parseUrl(url, key){
		var 
			pattern = "^(([^:/\\?#]+):)?(//(([^:/\\?#]*)(?::([^/\\?#]*))?))?([^\\?#]*)(\\?([^#]*))?(#(.*))?$",
			rx = new RegExp(pattern),
        	parts = rx.exec(url || location.href),
        	parsed = {
				href: 			parts[0] || "",
		        protocol: 		parts[1] || "",
		        host: 			parts[4] || "",
		        hostname: 		parts[5] || "",
		        port: 			parts[6] || "",
		        pathname: 		parts[7] || "/",
		        search: 		parts[8] || "",
		        hash: 			parts[10] || ""
        		};
        return key ? parsed[key] : parsed;
		}
		
	function getHostName(url){
		return parseUrl(url, 'host');
		}
		
	function UrlComposer(parts, query){
		var
			data = {
				/** @type {Array} */
				parts: [],
				/** @type {Object} */
				query:	{},
				/** @type {String} */
				hash:	undefined
				},
			/** 
			 * Public functionality 
			 */
			obj = {
				/** 
				 * Appends part(s)
				 * @return {UrlComposer}
				 */
				parts: function(){
					var 
						aNum = arguments.length;
					if (aNum == 1 && $.isArray(arguments[0])){
						for (var i = 0, l = arguments[0].length; i < l; i++) {
							obj.parts(arguments[0][i]);
							}
						}
					else if (aNum > 1){
						for (var i = 0, l = arguments.length; i < l; i++) {
							obj.parts(arguments[i]);
							}
						}
					else if (aNum == 1 && typeof arguments[0] != 'undefined'){
						data.parts.push(arguments[0]);
						}
					return this;
					},
				/** 
				 * Appends query param(s)
				 * @return {UrlComposer}
				 */
				query: function(){
					var 
						aNum = arguments.length;
					if (aNum == 2 && 
						!$.isPlainObject(arguments[0]) && 
						!$.isPlainObject(arguments[1])){
						data.query[arguments[0]] = ('boolean' == (typeof arguments[1]).toLowerCase()) 
							? +arguments[1]
							: arguments[1]
							
						}
					else if (aNum >= 2){
						for (var i = 0, l = arguments.length; i < l; i++) {
							obj.query(arguments[i]);
							}
						}
					else if (aNum == 1 && $.isPlainObject(arguments[0])){
						data.query = $.extend({}, data.query, arguments[0]);
						}
					return this;
					},
				/** 
				 * Sets hash param 
				 * @param {String}
				 * @return {UrlComposer}
				 */
				hash: function(hash){
					if (typeof hash == 'undefined'){
						data.hash = undefined;
						}
					else{
						data.hash = hash.toString();
						}
					return this;
					},
				/** 
				 * Parses given url to inner data
				 * @param {String} url
				 * @return {UrlComposer()}
				 */	
				parse: function(url){
					if (typeof url == 'undefined'){
						url = location.href;
						}
					var
						pu = parseUrl(url),
						qp,
						_qp;
					obj.parts(pu.pathname.split('index.html'));
					if (pu.search){
						qp = pu.search.substr(1).split('&');
						
						for (var i = 0, l = qp.length; i < l; i++) {
							_qp = qp[i].split('=');
							obj.query(_qp[0], _qp[1]);
							}
						}
					if (pu.hash){
						data.hash = pu.hash;
						}
					return this;
					},
				/** 
				 * Returns url as string
				 * @return {String}
				 */
				compose:function(){
					var 
						res = '',
						queryParts = [];
					$.each(data.query, function(key){
						queryParts.push(key + '=' + this.toString());
						});
					return data.parts.join('index.html') + 
						(queryParts.length
							? '?' + queryParts.join('&')
							: ''
							) + 
						(typeof data.hash != 'undefined'
							? '#' + data.hash
							: ''
							);
					},
				/** 
				 * @return {String}
				 */
				toString: function(){
					return this.compose();
					},
				/** 
				 * @return {data}
				 */
				toObject: function(){
					return $.extend({}, data);
					}
				};
		if (parts && parts.length){
			obj.parts(parts);
			}
		if (query){
			obj.query(query);
			}
		return obj;
		}
		
		
	/** 
 * Hash control
 */
var LocationHash = (function(){
	var
		listeners = [],
		/** @type {String} */
		lastHashStr = undefined,
		onChange = function(){
			var 
				/** @type {obj.Data()} */
				dataToSend;
			if ((typeof lastHashStr != 'undefined') && location.hash.substr(1) == lastHashStr){
				return;
				}
			obj.getData(true);
			dataToSend = obj.Data(data);
			lastHashStr = data.raw;
			for (var i = 0, l = listeners.length; i < l; i++) {
				listeners[i](dataToSend);
				}
			},
		encodeHashValue = function(v){
			return encodeURIComponent(v);
			},
		decodeHashValue = function(v){
			return decodeURIComponent(v);
			},
		/** 
		 * @param {String}
		 * @return {obj.Data()}
		 */
		decodeHash = function(hash){
			var 
				/** @type {obj.Data()} */
				decoded,
				/** @type {Array} */
				p,
				/** @type {String} */
				partsStr,
				/** @type {String} */
				paramsStr,
				/** @type {Array} */
				params,
				/** @type {Array} */
				_param;
				
			if (typeof hash == 'undefined'){
				hash = location.hash.substr(1);
				}
			decoded = obj.Data({
				raw: hash
				});
				
			p = hash.split(obj.paramsInitSign);
			partsStr = p.shift();
			paramsStr = p.join(obj.paramsInitSign);
			decoded.parts = partsStr.split(obj.partsSeparator);
			if (paramsStr){
				params = paramsStr.split(obj.paramsSeparator);
				for (var i = 0, l = params.length; i < l; i++) {
					_param = params[i].split('=');
					if (_param[0] && (typeof _param[1] != 'undefined')){
						decoded.params[decodeHashValue(_param[0])] = decodeHashValue(_param[1]);
						}
					}
				}
			return decoded;
			},
		/** 
		 * @param {obj.Data()}
		 * @return {String}
		 */
		encodeHash = function(d){
			var
				/** @type {String} */
				partsStr,
				/** @type {Array} */
				_params = [],
				/** @type {String} */
				paramsStr;
			if (d.parts){
				partsStr = d.parts.join(obj.partsSeparator);
				}
			if (d.params){
				$.each(d.params, function(key){
					if (typeof this != 'undefined'){
						_params.push([encodeHashValue(key), encodeHashValue(this.toString())].join('='));
						}
					})
				if (_params.length){
					paramsStr = obj.paramsInitSign + _params.join(obj.paramsSeparator);
					}
				}
			return [partsStr, paramsStr].join('');
			},
			
		setHash = function(hash, skipHistory){
			var hp;
			lastHashStr = hash;
			data = undefined;
			if (!location.hash && !hash){
				return;
				}
			if (skipHistory){
				hp = location.href.split('#');
				hp[1] = hash;
				location.replace(hp.join('#'));
				}
			else{
				location.hash = hash;
				}
			},
		/** @type {obj.Data()} */
		data,
		obj = {
			partsSeparator		: '/',
			paramsSeparator		: '&',
			paramsInitSign		: ':',
			addListener: function(f){
				if (!$.isFunction(f)){
					return;
					}
				listeners.push(f);
				},
				
			/** 
			 * @param {Boolean} force parse hash
			 * @return {LocationHash.Data()}
			 */
			getData: function(force){
				if (!data || force){
					data = decodeHash();
					}
				return data;
				},
				
			update: function(){
				var 
					/** @type {String} */
					hash,
					skipHistory = false,
					args = Array.prototype.slice.call(arguments);
				if (args[0] === false || args[0] === true){
					skipHistory = args.shift();
					}
				switch (args.length){
					case 0:
						return;
					case 1:	
						hash = encodeHash(this.Data(args[0]));
						break;
					case 2:
					default:
						hash = encodeHash(this.Data({
							parts:	setArray(args[0]),
							params:	args[1]
							}));
						break;
					}
				if (typeof hash != 'undefined'){
					setHash(hash, skipHistory);
					}
				
				},
				
			extend: function(){
				var
					skipHistory = false,
					args = Array.prototype.slice.call(arguments);
				if (args[0] === false || args[0] === true){
					skipHistory = args.shift();
					}
				setHash(
					encodeHash(
						this.Data(
							$.extend(
								{}, 
								this.getData(), 
								args[0]
								)
							)
						), 
					skipHistory
					);
				},
				
			Data: function(_d){
				var 
					d = {
						/** 
						 * Pseudo 'query'-parts of hash
						 * @type {Array}
						 */
						parts: 		[],
						/** 
						 * Pseudo 'get'-params of hash
						 * @type {Object}
						 */
						params:		{},
						/** 
						 * Pseudo raw hash as string (without #)
						 * @type {String} 
						 */
						raw:		'',
						update:		function(_upd){
							$.extend(d, _upd)
							},
						toString:	function(){
							return encodeHash(this);
							}
						};
				if ($.isPlainObject(_d)){
					$.extend(d, _d);
					}
				else if (_d){
					d = decodeHash(_d.toString().split('#').pop());
					}
				return d;
				},
				
			getParamsStr: function(){
				var
					/** @type {String} */
					h = location.hash.substr(1),
					p = h.split(this.paramsInitSign);
				return p.length > 1 ? p.pop() : ''; 
				}
			};
			
	$(window).bind('hashchange', onChange);
	
	return obj;
	})();

	
	
function Insulator( settings ){
		var
			_settings = {
				prefix : 'c',
				sprt : '--'
				},
			$container,
			/** 
			 * Inner storage for jQuery containers keyed by theirs unprefixed class names
			 */
			innerContainers = {};
		settings && $.extend( _settings, settings );
		
		$container = _settings.container
			? $( _settings.container )
			: $( document.body );
		
		/** 
		 * Composes and returns class expression with prefix
		 * @param {String} class base name
		 */
		function _ic( c ){
			return c 
				? j( _settings.prefix, _settings.sprt, String( c ).split( '.' ).join( _settings.sprt ) )
				: _settings.prefix;
			}
			
		/** 
		 * Composes and returns class expression with prefix
		 * The same as _ic but previously parses given class base name
		 * and replace all dots to separators
		 * @param {String} class base name
		 */
		function _icp( c ){
			return c
				? j( _settings.prefix, _settings.sprt, String( c ).split( '.' ).join( _settings.sprt ) )
				: _settings.prefix;
			}
			
		/** 
		 * Serializes data in element class uses given class prefix
		 * @param {String} c class base name
		 * @param {Object} d data to serialize
		 * @return {String} class name
		 */
		function _icd( c , d ){
			var
				p = c 
					? j( _settings.prefix , _settings.sprt , c ) 
					: _settings.prefix,
				res = [ p ];
			for( var i in d ){
				if ( d.hasOwnProperty( i ) ){
					res.push( j( p , _settings.sprt , i , _settings.sprt , d[ i ]  ) );
					}
				}
			return res.join(' ')
			}
		
		function _icvv( c , key , value ){
			var
				p = c 
					? j( _settings.prefix , _settings.sprt , String( c ).split( '.' ).join( _settings.sprt ) ) 
					: _settings.prefix;
			return j( p , _settings.sprt , key , _settings.sprt , value  );
			}	
			
		function icvv( c , key , value ){
			return j( '.' , _icvv( c, key, value )  );
			}	
			
		function _icv( c , key , value ){
			var
				_c = String( c ).split( '.' ).join( _settings.sprt ),
				p = c 
					? j( _settings.prefix , _settings.sprt , _c ) 
					: _settings.prefix;
			return [ p , _icvv( _c , key , value ) ].join(' ');
			}
			
		
			
		function _icvSearch( $c , c , key ){
			var
				p = c 
					? j( _settings.prefix , _settings.sprt , c ) 
					: _settings.prefix;
			return $( $c ).searchInClass( j( p , _settings.sprt , key, _settings.sprt ) );
			}
		
		/** 
		 * Composes and returns item jQuery class expression with prefix
		 */
		function ic( c ){
			return c
				? j( '.', _settings.prefix, _settings.sprt,  String( c ).split( '.' ).join( _settings.sprt ) )
				: j( '.', _settings.prefix )
			}
			
			
		/** 
		 * Gets inner container by its class (without prefix)
		 * Caches results in <code>innerContainers</code>, so each container searched at once only. 
		 * If given second <code>elem</code> param container will be created on fly (with prefixed class)
		 * And if given third <code>parent</code> it will be appended to it
		 * @param {String} c class name
		 * @param @optional {DOMElement} 
		 * @param @optional {String} parent unprefixed class of parent element to append new one to 
		 * @return {jQuery}
		 */
		function $ic(){
			var 
				args = Array.prototype.slice.call(arguments),
				force = false,
				c,
				elem,
				parent;
			if ( args[0] === true ){
				force = true;
				args.shift();
				}
			c = args.shift();
			elem = args.shift();
			parent = args.shift();
			
			
			if ( typeof elem != 'undefined' ){
				/* Creating */
				innerContainers[ c ] = $( elem ).addClass( _ic( c ) );
				if ( parent ){
					innerContainers[ c ].appendTo( $ic( parent ).eq( 0 ) );
					}
				else {
					innerContainers[ c ].appendTo( $container );
					}
				}
			else if ( ! ( c in innerContainers ) || force ){
				innerContainers[ c ] = $container.find( ic( c ) ); 
				}
			return innerContainers[ c ];
			}
			
		function setContainer( c ){
			$container = $( c );
			}
			
		function reset(){
			innerContainers = [];
			}
			
			
		/** 
		 * Public of Insulator
		 */
		return {
			/** 
			 * 
			 * @type {Function}
			 * @return {jQuery} 
			 */
			c            : $ic,
			cl           : ic,
			_cl          : _ic,
			_clp         : _icp,
			_d           : _icd,
			_v           : _icv,
			_vv          : _icvv,
			vv           : icvv,
			_s           : _icvSearch,
			setContainer : setContainer,
			reset        : reset
			}
		}	
	
/** 
 * Base page services
 */
var SitePage = (function(){
	var
		/** @type {String} */
		hashArraysDelimiter 	= ',',
		
		_loadedJs 				= {},
		_loadedCss 				= {},
		STATUS_LOADING 			= 1,
		STATUS_LOADED_SUCCESS 	= 10,
		STATUS_LOADED_ERROR 	= 100,
		
		encodeHashValue = function(v){
			return encodeURIComponent(v);
			},
			
		decodeHashValue = function(v){
			return decodeURIComponent(v);
			},
			
		prepareHash = function(h){
			var strHash='';
			if (is_object(h)){
				var arHash=[];
				for (var pName in h){
					var prop=h[pName];
					if ((is_string(prop) || is_numeric(prop)) && typeof(prop)!='undefined'){
						arHash.push(pName + '=' + encodeHashValue(String(prop)));
						}
					else if (is_array(prop)){
						arHash.push(pName + '=' + encodeHashValue(prop.join(hashArraysDelimiter)));
						}
					}
				strHash=arHash.join('&');
				}
			else if (is_string(h)){
				strHash=h;
				}
			else{
				return false;
				}
			return strHash;
			},
		
		/** 
		 * SitePage public interface
		 */
	 	obj = {
	 		
	 		/** @type {String} */
	 		redirect:function(page){
				if(!page) page="index.html";
				if (page.search(/^https?\:\/\//i)<0){
					if (page.substr(0,1)!='index.html')
						page="/"+page;
					page=SITE_URL+page;
					}
				window.location=page;
				return false;
				},
				
			refresh:function(){
				window.location.reload(false);
				},
				
			getHash:function(){
				return (location.hash).substr(1);
				},
				
			setHash:function(h){
				var 
					strHash=prepareHash(h),
					currEmptyHash=location.href.charAt(location.href.length-1)=='#';
				if(currEmptyHash){
					window.location=location.href+(strHash||'');
					}
				else if (strHash || location.hash){
					location.hash=(strHash||'');
					}
				return strHash;
				},
				
			parseHash:function(){
				var
					h=this.getHash(),
					params={};
				if (!isset(h) || h==''){
					return false;
					}
				var arHash=h.split('&');			
				for (var i in arHash){
					var prop=arHash[i];				
					if (!is_string(prop)){
						continue;
						}
					var p=prop.split('=');					
					if (!p.length || p.length<2){
						continue;
						}
					var 
						field = p[0],
						value = decodeHashValue(p[1]);
					/*test array*/
					var parts=value.split(hashArraysDelimiter);
					if (parts.length>1){
						value=parts;					
						}
					params[field]=value;				
					}			
				return params;
				},
			
			appendHash:function(p){
				this.setHash($.extend(this.parseHash(), p));
				},
				
			removeFromHash:function(p){
				var 
					hash = this.parseHash();
				if (hash){
					delete hash[p];
					this.setHash(hash);
					}
				},
				
			setTitle:function(t, postfix){
				if (t){
					document.title = postfix
						? [t, postfix].join(' | ')
						: t;
					}
				},
				
			loadJs: function(){
				var 
					Load = function(src, onload, onerror){
						var 
							documentHead = document.getElementsByTagName("head")[0],
							s,
							_onload,
							_isLoaded = false,
							complete = function(success){
								var listeners = [];
								if (_loadedJs[src].status != STATUS_LOADING){
									/* Preventing double running */
									return false;
									}
								if (success){
									_loadedJs[src].status = STATUS_LOADED_SUCCESS;
									listeners = _loadedJs[src]['listenersSuccess'];
									}
								else{
									_loadedJs[src].status = STATUS_LOADED_ERROR;
									listeners = _loadedJs[src]['listenersError'];
									}
								if (listeners.length){
									for (var i = 0, l = listeners.length; i < l; i++) {
										listeners[i] && listeners[i]();
										}
									}
								};
						if (!documentHead || !documentHead.firstChild){
							throw new Error('Cannot load script until DOM ready');
							}
						if (onerror === false){
							onerror = onload;
							}
						if (_loadedJs[src] && _loadedJs[src].status){
							switch (_loadedJs[src].status){
								case STATUS_LOADING:
									_loadedJs[src].listenersSuccess.push(onload);
									_loadedJs[src].listenersError.push(onerror);
									return true;
								case STATUS_LOADED_SUCCESS:
									onload && onload();
									return true;
								case STATUS_LOADED_ERROR:
									onerror && onerror();
									return true;
								}
							}	
							
						_loadedJs[src] = {
							status: STATUS_LOADING,
							listenersSuccess: [onload],
							listenersError: [onerror]
							};
							
						s = document.createElement("script");
						s.charset = "utf-8";
						s.src = src;
						s.onload = function(res){
							complete(true);
							};
						s.onerror = function(){
							complete(false);
							}
						s.onreadystatechange = function() {
							if (this.readyState == 'complete' || this.readyState == 'loaded') {
								s.onload();
								}
							}
						documentHead.insertBefore(s, documentHead.firstChild);
						},
					scripts = [],
					onload,
					onerror,
					_src,
					_total,
					_loaded;
				if (arguments.length){
					for (var i = 0, l = arguments.length; i < l; i++) {
						if ($.isFunction(arguments[i])){
							if (onload == undefined){
								onload = arguments[i];
								}
							else if (onerror == undefined){
								onerror = arguments[i];
								}
							else{
								break;
								}
							}
						else if (arguments[i] ===  false){
							if (onload != undefined && onerror == undefined){
								onerror = onload;
								}
							}
						else{
							_src = arguments[i].toString();
							if (
								_src.search(/https?:\/\//) !== 0 && 
								_src.charAt(0) != 'index.html'
								){
								/* Converting relative urls to absolute using global url value */
								_src = '/' + _src
								}
							scripts.push(_src);
							}
						}
					_total = scripts.length;
					_loaded = 0;
					for (var i = 0; i < _total; i++) {
						_src = scripts[i];
						Load(_src, 
							function(){
								if (++_loaded >= _total){
									onload && onload();
									}
								},
							function(){
								onerror && onerror(_src);
								});
						}
					}
				},
				
			loadCss : function(){
				var 
					_src,
					Load = function(src){
						var 
							documentHead = document.getElementsByTagName("head")[0],
							s;
						if (_loadedCss[src] && _loadedCss[src].status == STATUS_LOADED_SUCCESS){
							/* Was loaded earlier */
							return true;
							}
						if (!documentHead || !documentHead.firstChild){
							throw new Error('Cannot load css until DOM ready');
							}
							
						s = document.createElement("link");
						s.rel = 'stylesheet';
						s.href = src;
						/* Inserting link element after all other to allow redeclare some rules */
						documentHead.appendChild(s);
						_loadedCss[src] = {
							status: STATUS_LOADED_SUCCESS
							}
						};
				if (arguments.length){
					
					for (var i = 0, l = arguments.length; i < l; i++) {
						_src = arguments[i];	
						if (
							_src.search(/https?:\/\//) !== 0 && 
							_src.charAt(0) != 'index.html'
							){
							/* Converting relative urls to absolute using global url value */
							_src = '/' + _src;
							}
						Load(_src);
						}
					}
				}
	 		};
	 		
	 return obj;
	})();	
/*Request*/	
	$.request=function(data){	
		var 
			clientSuccess=data.success,
			clientError=data.error;
		
		data.success=function(res){
			$.status().hide();
			clientSuccess && clientSuccess(res);  
			};
		data.error=function(res){
			$.status().hide();
			clientError && clientError(res);
			}
		!data.quite && $.status.progress();
		
		if (!data.data){
			data.data={};
			}
		if (!data.url){
			data.url=location.pathname;
			}
		$.ajax($.extend({},{
			dataType:'json'
			,type:'GET'		
			},data));	
		}
/* Status */
$.status = function(msg) {
	var 
		self=$.status,
		_timer,
		resetTimer=function(){
			clearTimeout(_timer);
			_timer=undefined;
			};
	
	!$.status.isInitialized && $.extend($.status,{
		settings:{
			delayOff:1000
			,align:'center'
			,topAttach:true
			,defaultProgressMsg:_( 'core:status_loading' )
			,defaultErrorMsg: _( 'core:status_error' )
			,containerCss:{
//				position:'static'				
				}			
			,hiddenCss:{
				top:-1000
				}
			,visibleCss:{
				top:''
				}
			}
		,initialize:function(){
			self.container=$('<div id="statusbar" />').css(self.settings.containerCss).css(self.settings.hiddenCss).appendTo(document.body);
			self.bindEvents();
			self.isInitialized=true;
			return self;
			}
		,bindEvents:function(){
			self.container.click(function(e){
				var target=$(e.target);
				if (target.is('a')){
					var action=searchInClass(target,'action-');
					if ($.isFunction(window[action])){
						window[action]();
						return false;
						}
					return true;
					}
				else{
					self.hide();
					}
				});
			return self;}
		,hide:function(){
			self.container.css(self.settings.hiddenCss);
			resetTimer(_timer);
			return self;
			}		
		,show:function(){
			self.container.css(self.settings.visibleCss);
			self.place();
			return self;
			}
		,place:function(){
			if (self.settings.align=='center'){
				self.container.css({
					left:'50%',
					marginLeft: - self.container[0].clientWidth / 2
					});
				}
			return self;
			}
		,msg:function(msg,cl){
			self.container.attr('class',cl||'').html('<strong>'+msg+'</strong>');
			self.show();
			return self;
			}
		,msgTmp:function(msg,cl){
			self.msg(msg,cl).show();
			resetTimer(_timer);
			_timer=setTimeout(function(){				
				_timer && self.hide();
				resetTimer();
				},self.settings.delayOff);
			return self;
			}
		,msgProgress:function(msg){
			resetTimer();
			self.msg(msg || self.settings.defaultProgressMsg, 'progress');
			return self;
			}
		,msgError:function(msg){
			resetTimer();
			self.msgTmp(msg||self.settings.defaultErrorMsg,'error');
			return self;
			}
		,msgErrorSticky:function(msg){
			resetTimer();
			self.msg(msg||self.settings.defaultErrorMsg,'error');
			return self;
			}
		}) && $.status.initialize();
	if (msg){
		$.status.msgTmp(msg);
		}
	return $.status;
	};	
$.status.progress=function(msg){
	return $.status().msgProgress(msg);
	};
$.status.error=function(msg){
	return $.status().msgError(msg);
	}
$.status.errorSticky=function(msg){
	return $.status().msgErrorSticky(msg);
	}
	
	function isEmail(str){
		var pt=/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i;
		return str?pt.test(str):false;
		}
	
	function getNumeralEndingType(num){
		var 
			rm=num%10,
			type=0;
		if (rm>0 && rm<=4){
			type=rm;
			}
		if (num%100>=11 && num%100<=14){
			type=0;
			}
		return type;
		}
	
	function getPopped(str,delimiter){
		if (!delimiter){
			delimiter='_';			
			}
		var parts=str.split(delimiter);
		parts.pop();
		return parts.join(delimiter);		
		}
	
	function plural(){
		var
			num = arguments[0],
			endings = Array.prototype.slice.call(arguments, 1, 4),
			replace = !! arguments[4],
			r10, r100, plr;
		if (isNaN(num)){
			return;
			}
		if (! endings.length){
			return num;
			}
		r10 = num % 10;
		r100 = num % 100;
		plr = (r10 == 1 && r100 != 11)
			? 0
			: (
				(r10 >= 2 && r10 <= 4 && (r100 < 10 || r100 >= 20) ) 
					? 1 
					: 2
				);
		return replace 
			? endings[plr].replace('%1', num)
			: j( num, ' ', endings[plr] );
		}	
		
	String.prototype.popped = function(delimiter){
		if (!delimiter){
			delimiter = '_';			
			}
		var parts = this.split(delimiter);
		parts.pop();
		return parts.join(delimiter);
		}
		
	String.prototype.firstCharUpper = function(){
		return this.substr(0,1).toUpperCase()+this.substr(1)
		}
		
	String.prototype.isNullDate = function(){
		return (this == "0000-00-00 00:00:00");
		}
		
	String.prototype.html_entity_decode = function(){
		return this.replace_multiply([
			 [/\&nbsp\;/,' '],
			 [/\&mdash\;/,'—'],
			 [/\&ndash\;/,'–'],
			 [/\&quot\;/,'"'],
			 [/\&amp\;/,'&'],
			 [/\&laquo\;/,'«'],
			 [/\&raquo\;/,'»'],
			 [/\&copy\;/,'©']
			 //TODO and on, and on..
			 ]);
		}
	
	function html_entity_decode(str){
		return str 
			? String(str).html_entity_decode()
			: '';
		}
	function strip_html_entities(str){
		return str 
			? String(str).replace(/\&[a-z]+;/gi, '')
			: '';
		}
		
	function htmlspecialchars(str){
		return str ? String(str).htmlspecialchars() : '';
		}
		
	String.prototype.htmlspecialchars = function(){
		var s=String(this);
		s=s.replace(/\&(?:.{6})?/g,function(p,v1,v2){
			if (/^\&(nbsp|amp|laquo|raquo|quot);/.test(p)){
				return p;
				}
			return '&amp;'+p.substr(1);
			});
		s=s.replace_multiply(
			[
			 ["<",'&lt;'],
			 [">",'&gt;'],
			 ["\"",'&quot;'],
			 ["«",'&laquo;'],
			 ["»",'&raquo;']
			 ]
			);
		return s;
		//"
		}
		
	function htmlspecialquotes(str){
		return str?str.replace_multiply(
			[
			 [/\"/,'&quot;'],
			 [/«/,'&laquo;'],
			 [/»/,'&raquo;']
			 ]
			):'';
		}
	
	function strip_tags(str, inc){
		if (!str){
			return '';
			}
		var pt = '<.*?>';
		if (inc){
			pt = '<\\/?\s*(?:' + ( $.isArray(inc) ? inc.join('|') : inc.toString() ) + ')(\\s[^>]+)*\\/?>';
			}
		return str.toString().replace( new RegExp(pt, 'g') ,'');
		}	
		
	function typo(str){
		str = str.toString();
		str = str.replace(/([\s\,\.\;\?\!\:])([а-яА-ЯёЁ]{1,2})\s/g, "$1$2&nbsp;");
		str = str.replace(/([\s\,\.\;\?\!\:])(\d+)\s/g, "$1$2&nbsp;");
		str = str.replace(/([\s\,\.\;\?\!\:])\"([а-яА-ЯёЁ0-9\,\!\:\-\s]+)\"([\s\,\.\;\?\!\:])/g, "$1&laquo;$2&raquo;$3");
		return str;
		}
		
	String.prototype.replace_multiply = function(data){
		var s=this;
		for (var i in data){
			var d=data[i];
			if (!d || !isset(d[0]) || !isset(d[1])){
				continue;
				}
			if (d[0] instanceof RegExp){
				while(s.search(d[0])>=0){
					s=s.replace(d[0],d[1]);	
					}
				}
			else{
				s = s.replace(new RegExp(d[0],"g"),d[1]);	
				}
			}		
		return s;
		}
	String.prototype.nl2br = function(){
		return NtoBR( this );
		}
		
	String.prototype.br2nl = function(){
		return BRtoN( this );
		}
		
	String.prototype.truncate = function( len , ending ){
		ending = ending || '...';
		return this.length <= len + String( ending ).length 
			? this 
			: this.slice(0, len || 30) + (ending || '...');
		}
	/** 
	 * Truncates string to given length at word boundaries
	 * @param {Number} len
	 * @param {String} ending
	 * @return {String}
	 */
	String.prototype.cutText = function( len, ending, minLen ){
		var 
			bits = this.split('');
		if (bits.length > len) {
			for (i = bits.length - 1; i > -1; --i) {
				if (i > len) {
					bits.length = i;
					}
				else{
					if ( ! isNaN( minLen ) && i < minLen ){
						bits.length = len;
						break;
						}
					else if (' ' === bits[i]) {
						bits.length = i;
						break;
						}
					}
				}
				bits.push( ending || '...' );
			}
		return bits.join('');
		}
		
	String.prototype.rmnl = function(){
		var tmpl=new RegExp(/\r?\n/i);
		return this.replace_multiply(
			[
			 [/\r?\n/i,''],
			 [/\t/,'']
			 ]
			);
		}
	
	String.prototype.dateStr=function(){
		if (this.isNullDate()){
			return;
			}
		var dt=new Date();			
		return dt.getFromDT(this).getReadable();
		}
		
	String.prototype.dateStrFull=function(){
		if (this.isNullDate()){
			return;
			}
		var dt=new Date();			
		return dt.getFromDT(this).getReadableFull();
		}
		
	String.prototype.dateReadableSimpleStr=function(){
		if (!this.length || this.isNullDate()){
			return;
			}
		var dt=new Date();			
		return dt.getFromDT(this).getReadableSimple();
		}
	
	String.prototype.dateGetHoursFromDt=function(){		
		if (this.isNullDate()){
			return;
			}
		var dt=new Date();			
		return String(dt.getFromDT(this).getHours()).setDigits();
		}
		
	String.prototype.dateGetMinutesFromDt=function(){
		if (this.isNullDate()){
			return;
			}
		var dt=new Date();		
		return String(dt.getFromDT(this).getMinutes()).setDigits();
		}
	
	String.prototype.dateFromDt=function(){
		if (this.isNullDate()){
			return;
			}
		return (new Date()).getFromDT(this);
		}
		
	String.prototype.dateFromTs=function(){
		if (this.isNullDate()){
			return;
			}
		return (new Date()).getFromTimeStamp(this);
		}

	String.prototype.dateFromTsStr=function(){
		return (new Date()).getFromTsStr(this);
		}
		
	String.prototype.isTime=function(){
		return (this.search(/^\d{1,2}\:\d{1,2}(\:\d{1,2})?$/)>=0);
		}
		
	String.prototype.isDate=function(){
		return this.match(/^\d{4}\-\d{2}\-\d{2}(\s\d{2}:\d{2}:\d{2})?$/);
		}
		
	String.prototype.parseTime=function(){
		if (!this.isTime()){
			return {};
			}
		var d=this.split(':');		
		return {'h':Number(d[0]),'m':Number(d[1]),'s':Number(d[2])};
		}
	
	String.prototype.setDigits=function(num){
		if (isNaN(num)){
			num = 2;
			}
		var 
			/** @type {String} */
			str = this,
			sign = '',
			bibb = '',
			bibbLength = 0;
		if (str.charAt(0) == '-'){
			sign = '-';
			str = str.slice(1);
			}
		if (str.length < num){
			bibbLength = num - str.length;
			for (var i = 0; i < bibbLength; i++){
				bibb += '0';
				}
			str = bibb + str;
			}
		return sign + str;
		}
		
	String.prototype.twoDigits=function(){
		if (this.length<2){
			return '0'+this;
			}
		return this;
		}
	
	
/* Numbers */
	Number.prototype.setDigits=function(num){
		return (String(this)).setDigits(num);
		}
		
	Number.prototype.between=function(a,b){
		return ( Math.min ( Math.max(this,Math.min(a,b)), Math.max(a,b)) );		
		}
	
	Number.prototype.isBetween=function(a,b){
		return (this>a && this<b)
		}
		
	Number.prototype.isBetween_s=function(a,b){
		return (this>=a && this<=b)
		}
		
	Number.prototype.format=function(){
		return String(this).numberFormat();
		}
		
	function outputFormat(v){
		if (is_numeric(v)){
			v=Number(v).format();
			}
		return v;
		}
		
	Number.prototype.roundFloat=function(x){
		x = (x==undefined ? 2 : x);
		return Math.round(this*Math.pow(10,x))/Math.pow(10,x); 
		}
		
	String.prototype.numberFormat=function(tailLength){
		var 			
			str = tailLength != undefined 
				? String(Number(this).roundFloat(tailLength)) 
				: this,
			decParts = str.split('.'),
			intStr = decParts.shift(),
			fractionStr = decParts.shift(),
			resStr = '',
			parts = [];
		while(intStr.length > 2){
			parts.unshift(intStr.substr(intStr.length - 3, intStr.length));
			intStr = intStr.substr(0, intStr.length - 3);
			}
		if (intStr.length){
			parts.unshift(intStr);
			}
		if (tailLength){
			fractionStr = (function(){
				var r='';
				fractionStr==undefined && (fractionStr='');				
				if (fractionStr.length<tailLength){
					for(var i=0;i<(tailLength-fractionStr.length);i++,r+='0');
					}
				return fractionStr+r;
				})();
			}
		return [
			'<span class="nmf"><span class="nmf-g">', 
			parts.join('</span><span class="nmf-g">'), 
			'</span>',(fractionStr ? ',' + fractionStr : '' ),  
			'</span>'].join('');	
		}

/** 
 *  Converts a string containing an (IPv4) Internet Protocol dotted address into a proper address  
 *  @example 1: ip2long('192.0.34.166');    
 *  @returns 1: 3221234342
 *  @example 2: ip2long('0.0xABCDEF');
 *  @returns 2: 11259375
 *  @example 3: ip2long('255.255.255.256');
 *  @returns 3: false    var i = 0;
 */
function ip2long(ip_address) {
  var parts = ip_address.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
  return parts
    ? parts[1] * 16777216 + parts[2] * 65536 + parts[3] * 256 + parts[4] * 1
    : false;
	}
	
 /**
  * Converts an (IPv4) Internet network address into a string in Internet standard dotted format  
  *  @example 1: long2ip( 3221234342 );
  *  @returns 1: '192.0.34.166'
  */
 function long2ip( proper_address ) {
    var output = false;    
    if ( !isNaN( proper_address ) && ( proper_address >= 0 || proper_address <= 4294967295 ) ) {
        output = Math.floor(proper_address / Math.pow( 256, 3 ) ) + '.' +
            Math.floor( ( proper_address % Math.pow( 256, 3 ) ) / Math.pow( 256, 2 ) ) + '.' +
            Math.floor( ( ( proper_address % Math.pow( 256, 3 ) )  % Math.pow( 256, 2 ) ) / Math.pow( 256, 1 ) ) + '.' +            Math.floor( ( ( ( proper_address % Math.pow( 256, 3 ) ) % Math.pow( 256, 2 ) ) % Math.pow( 256, 1 ) ) / Math.pow( 256, 0 ) );
		}
    return output;
	}

/** 
 * Returns the decimal equivalent of the binary number
 * @example 1: bindec('110011');
 * @returns 1: 51
 * @example 2: bindec('000110011');
 * @returns 2: 51    
 * @example 3: bindec('111');
 * @returns 3: 7  
 */
function bindec(binary_string) {
    binary_string = (binary_string+'').replace(/[^01]/gi, '');
    return parseInt(binary_string, 2);
	}
	
/** 
 * Returns a string containing a binary representation of the number
 * @example 1: decbin(12);
 * @returns 1: '1100'
 * @example 2: decbin(26);
 * @returns 2: '11010'
 * @example 3: decbin('26');   
 * @returns 3: '11010'
 */
function decbin(number) {
    if (number < 0) {
		number = 0xFFFFFFFF + number + 1;
		}
    return parseInt(number, 10).toString(2);
    }

		
/* Dates */
	
	var 
		MONTHS = [
			_( 'core:January_gn' ), 	_( 'core:February_gn' ), 	_( 'core:March_gn' ),
			_( 'core:April_gn' ),		_( 'core:May_gn' ),			_( 'core:June_gn' ),
			_( 'core:July_gn' ),		_( 'core:August_gn' ),		_( 'core:September_gn' ),
			_( 'core:October_gn' ),		_( 'core:November_gn' ),	_( 'core:December_gn' )
			],
		MONTHS_SHORT = [
			_( 'core:Jan' ),			_( 'core:Feb' ),			_( 'core:Mar' ),
			_( 'core:Apr' ),			_( 'core:May_sh' ),			_( 'core:Jun' ),
			_( 'core:Jul' ),			_( 'core:Aug' ),			_( 'core:Sep' ),
			_( 'core:Oct' ),			_( 'core:Nov' ),			_( 'core:Dec' )],
		MONTHS_NOMINATIVE = [
			_( 'core:January' ),		_( 'core:February' ),		_( 'core:March' ),
			_( 'core:April' ),			_( 'core:May' ),			_( 'core:June' ),
			_( 'core:July' ),			_( 'core:August' ),			_( 'core:September' ),
			_( 'core:October' ),		_( 'core:November' ),		_( 'core:December' )],
		MONTHS_LENGTHS = [
			31, ( (new Date).getFullYear()%4 ? 28 :29 ),31,30,31,30,31,31,30,31,30,31],
		WEEKDAYS = [
			_( 'core:Mo' ), _( 'core:Tu' ), _( 'core:We' ), _( 'core:Th' ), _( 'core:Fr' ), _( 'core:Sa' ), _( 'core:Su' )
			],
		WEEKDAYS_FULL = [
			_( 'core:Monday' ), _( 'core:Tuesday' ), _( 'core:Wednesday' ), _( 'core:Thursday' ),
			_( 'core:Friday' ), _( 'core:Saturday' ), _( 'core:Sunday' )
			];
	
	$(function(){
		if ( window.monthsArray ){
			MONTHS = window.monthsArray;
			}
		})		
			
	function getMonthLength(m, y){
		return m == 1 
			? isLeapYear(y) ? 29 : 28 
			: MONTHS_LENGTHS[m];
		}
	function isLeapYear(y){
		if (!y){
			y=(new Date()).getFullYear();
			}
		return (new Date(y,1,29)).getMonth()==1?true:false;
		}
	Date.prototype.getReadable=function(){
		return this.getDate()+'&nbsp;'+MONTHS[this.getMonth()]+'&nbsp;'+this.getFullYear();
		}
	Date.prototype.getReadableShort=function(){
		return this.getDate()+'&nbsp;'+MONTHS_SHORT[this.getMonth()];
		}
		
	Date.prototype.getMonthReadable=function(){		
		return MONTHS_NOMINATIVE[this.getMonth()]+'&nbsp;'+this.getFullYear();	
		}
	
	Date.prototype.getWeekReadable=function(){
		var 
			week = this.duplicate().getWeek(),
			beginYear = week.begin.getFullYear() == week.end.getFullYear() 
				? '' 
				: ' '+week.begin.getFullYear();
		return [
			week.begin.getReadableShort(), 
			beginYear, 
			'&nbsp;&mdash; ', 
			week.end.getReadableShort(),
			' ', week.end.getFullYear()
			].join('');
		}
		
	Date.prototype.getWeekReadableShort = function(){
		var week = this.duplicate().getWeek();
		return [ 
			week.begin.format('d'+(week.begin.getMonth()==week.end.getMonth()?'':' M')),  
			'&nbsp;&mdash; ',  
			week.end.format('d M')
			].join('');
		}
	
	Date.prototype.getHourReadable = function(){
		return [
			this.duplicate().offset({hours:-1}).format('H:i'),
			'&nbsp;&mdash; ',
			this.format('H:i')
			].join('');
		}
	
	Date.prototype.getReadableFull = function(){
		return _(
			'-dateFullStr',
			this.getDate(),
			MONTHS[this.getMonth()],
			this.getFullYear(),
			this.getHours().setDigits(),
			this.getMinutes().setDigits()
			);
		}
		
	Date.prototype.getReadableSimple=function(){
		var 
			d = this.getDate().toString(),
			m = (this.getMonth()+1).toString(),
			y = this.getFullYear().toString();
		if (d.length<2) {
			d = "0"+d;
			}
		if (m.length < 2){
			m = "0"+m;		
			}
		var o=d+'.'+m+'.'+y;
		return o;	
		}
	
	Date.prototype.toDT=function(){		
		var d=this.getDate().toString(),
			m=(this.getMonth()+1).toString(),
			Y=this.getFullYear().toString(),
			H=this.getHours().toString(),
			i=this.getMinutes().toString(),
			s=this.getSeconds().toString();
		return [ 
			Y.setDigits(4), '-', 
			m.setDigits(2), '-', 
			d.setDigits(2), ' ', 
			H.setDigits(2), ':', 
			i.setDigits(2), ':', 
			s.setDigits(2)
			].join('');
		}
	Date.prototype.getDateStr = function(){
		return this.format('Y-m-d');
		}
	Date.prototype.getTimeStr = function(){
		return this.toDT().split(' ').pop();
		}
	
	Date.prototype.getTimeStamp = function(){
		var 
			d = this.getDate(),
			m = this.getMonth()+1,
			y = this.getFullYear();		
		if (d < 10) {
			d = "0" + d;
			}
		if (m < 10){
			m = "0" + m;	
			}
		return ["", y, m, d, "000000"].join('');
		}
		
	Date.prototype.getFullTimeStamp = function(){
		return this.format('YmdHis')
		}
		
	Date.prototype.getTsShort = function(){
		return [ 
			this.getFullYear().toString(),
			String(this.getMonth()+1).setDigits(), 
			String(this.getDate()).setDigits()
			].join('');
		}
	Date.prototype.getFromTimeStamp=function(ts){
		ts = ts + '';
		var 
			y = 	Number(ts.substr(0,4)),
			m = 	Number(ts.substr(4,2))-1,
			d = 	Number(ts.substr(6,2)) || 1,
			h = 	Number(ts.substr(8,2)) || 0,
			mn = 	Number(ts.substr(10,2)) || 0,
			s = 	Number(ts.substr(12,2)) || 0;

		/* Setting day to 1 for prevent month auto switching 
		 * until date is not set completely */
		this.setDate(1)
		
		this.setFullYear(y);
		this.setMonth(m);
		this.setDate(d);
		this.setHours(h);
		this.setMinutes(mn);
		this.setSeconds(s);
		return this;
		}
	
	Date.prototype.getFromDT=function(dt){
		dt=String(dt);	
		this.set({
			days:dt.substr(8,2),
			months:dt.substr(5,2)-1,
			years:parseInt(dt.substr(0,4)),
			hours:dt.substr(11,2)||0,
			minutes:dt.substr(14,2),
			seconds:dt.substr(17,2),
			milliseconds:0
			});
		return this;
		}
		
	Date.prototype.getFromTsStr=function(dt){
		var parts=dt.split('.');
		this.set(
			{
				years:Number(parts[2]),
				months:Number(parts[1]),
				days:Number(parts[0])
				}
			);
		return this;
		}
	
	/** 
	 * 
	 * @param {Object} sset
	 * @return {Date}
	 */
	Date.prototype['set']=function(sset){
		var 
			year=sset.year || this.getFullYear()
		if (isset(sset.days) && isset(sset.months) && getMonthLength(this.getMonth(),year)<Number(sset.days)){
			this.setMonth(sset.months);
			if (getMonthLength(this.getMonth(),year)<Number(sset.days)){
				this.setDate(getMonthLength(this.getMonth(),year));
				}
			else{
				this.setDate(sset.days);
				}
			}
		else{
			if (isset(sset.days)){
				this.setDate(sset.days);
				}			
			if (isset(sset.months)){
				if (getMonthLength(sset.months,year)<this.getDate()){				
					this.setDate(getMonthLength(sset.months,year));
					}
				this.setMonth(sset.months);
				}
			}
		if (isset(sset.years)){
			this.setFullYear(sset.years);
			}
		if (isset(sset.hours)){
			this.setHours(sset.hours);
			}
		if (isset(sset.minutes)){
			this.setMinutes(sset.minutes);
			}
		if (isset(sset.seconds)){
			this.setSeconds(sset.seconds);
			}
		if (isset(sset.milliseconds)){
			this.setMilliseconds(sset.milliseconds);
			}
		
		return this;
		}
	
	Date.prototype.offset=function(offset){
		var co={};
		if (offset.days){
			co['days']=this.getDate()+offset.days;
			}
		if (offset.months){
			co['months']=this.getMonth()+offset.months;
			}
		if (offset.years){
			co['years']=this.getFullYear()+offset.years;
			}
		if (offset.hours){
			co['hours']=this.getHours()+offset.hours;
			}
		if (offset.minutes){
			co['minutes']=this.getMinutes()+offset.minutes;
			}
		if (offset.seconds){
			co['seconds']=this.getSeconds()+offset.seconds;
			}
		this.set(co);
		return this;
		}
		
	Date.prototype.offsetDaysFromDate=function(dt,days){
		this.setDate(dt.getDate() + days);
		return this;
		}
		
	Date.prototype.offsetDays=function(days){
		return this.offsetDaysFromDate(this,days);
		}
		
	Date.prototype.offsetMonthsFromDate=function(dt,months){
		this.setMonth(this.getMonth()+(months||1));
		return this
		}
		
	Date.prototype.offsetMonths=function(months){
		return this.offsetMonthsFromDate(this,months)
		}

	Date.prototype.offsetYearsFromDate=function( dt, years ){
		this.setFullYear( this.getFullYear() + ( years || 0 ) );
		return this;
		}

	Date.prototype.offsetYears=function( years ){
		return this.offsetYearsFromDate( this, years );
		}

	/** 
	 * @return {Date}
	 **/
	Date.prototype.getNearestWeekday=function(weekday,direction){
		var steps=0;
		while(this.getDay()!=weekday){
			this.offsetDays(direction<0?-1:1);
			if (++steps>6){
				return false;
				}
			}
		return this;
		}
		
	Date.prototype.getLastFullWeekBegin=function(){
		return this.getNearestWeekday(1,-1).offsetDays(-1).getNearestWeekday(1,-1);
		}
		
	Date.prototype.getLastFullWeekEnd=function(){
		return this.getNearestWeekday(1,-1).offsetDays(-1);
		}
		
	Date.prototype.getLastFullMonthEnd=function(){
		this.setDate(1);
		return this.offsetDays(-1);
		}
		
	Date.prototype.getLastFullMonthBegin=function(){
		this.offsetMonths(-1)
		this.setDate(1);
		return this;
		}
		
	Date.prototype.getFullMonth=function(){
		var begin=this.duplicate();
		var end=this.duplicate();
		begin.setDate(1);
		end.offsetMonths(1).setDate(1);
		return {begin:begin,end:end};
		}
		
	Date.prototype.getFullDay=function(){
		var begin=this.duplicate();		
		var end=this.duplicate();
		begin.setHours(0);begin.setMinutes(0);begin.setSeconds(0);
		end.setHours(23);end.setMinutes(59);end.setSeconds(59);	
		return {begin:begin,end:end};
		}
		
	Date.prototype.getNextMonthBegin=function(){
		this.setDate(1);
		this.offsetMonths(1);		
		return this;
		}	
		
	Date.prototype.getWeek=function(){
		return {begin:this.duplicate().getNearestWeekday(1,-1),end:this.duplicate().getNearestWeekday(0,1)};
		}
		
	Date.prototype.getWeekday=function(){
		var wd=this.getDay();
		return WEEKDAYS[wd==0?6:wd-1];
		}
		
	Date.prototype.nullHms=function(){
		this.setHours(0);
		this.setMinutes(0);
		this.setSeconds(0);
		return this;
		}
	
		
	/** 
	 * Checks the equality of the date to another date using severity
	 * @param {Date} dt
	 * @param {String} severity
	 * @return {Boolean}
	 */
	Date.prototype.equal = function(dt, severity){
		if (!is_date(dt)){
			return false;
			}
		return(
			this.getFullYear() == dt.getFullYear() && (
			severity == 'year' || 
				this.getMonth() == dt.getMonth() && (
					severity == 'month' || 
						this.getDate() == dt.getDate()
					)
				)
			);
		}
		
	Date.prototype.equalMonth = function(dt){
		if (!is_date(dt)){
			return false;
			}
		return(
			this.getFullYear() == dt.getFullYear() &&
			this.getMonth() == dt.getMonth()
			);
		}
		
	Date.prototype.less=function(dt,equal){
		return(is_date(dt) && (
			(!equal && this.getTime()<dt.getTime()) ||
			(equal && this.getTime()<=dt.getTime())
			));
		}
		
	Date.prototype.greater=function(dt,equal){
		return(!!(is_date(dt) && (
			(!equal && this.getTime()>dt.getTime()) ||
			(equal && this.getTime()>=dt.getTime())
			)));
		}
		
	Date.prototype.between=function(dt1,dt2){
		return(is_date(dt1) && is_date(dt2) && this.getTime()>dt1.getTime() && this.getTime()<dt2.getTime());
		}
		
	Date.prototype.between_s=function(dt1,dt2){
		if (is_date(dt1) && is_date(dt2)){
			dt1.setMilliseconds(0);dt2.setMilliseconds(0);this.setMilliseconds(0);
			return (this.getTime()>=dt1.getTime() && this.getTime()<=dt2.getTime());
			}
		return false;		
		}
		
	Date.prototype.setBetween=function(dt1,dt2){
		if (this.less(dt1)){
			return this.duplicate(dt1);
			}
		else if (this.greater(dt2)){
			this.duplicate(dt2);
			}
		return this;
		}
		
	/** 
	 * 
	 * @param {Date} dt1
	 * @param {Date} dt2
	 * @return {Number}
	 */
	function getDaysDiff(dt1, dt2){
		return Math.round(
			(dt1
				.duplicate()
				.set({hours:0,minutes:0,seconds:0,milliseconds:0})
				.getTime() - 
			dt2
				.duplicate()
				.set({hours:0,minutes:0,seconds:0,milliseconds:0})
				.getTime()) / 
			(3600*24*1000)
			);
		}
		
	/** 
	 * 
	 * @param {Date} dt1
	 * @param {Date} dt2
	 * @return {Number}
	 */
	function getMonthsDiff(dt1, dt2){
		return Math.round(
			(dt1
				.duplicate()
				.set({days:1,hours:0,minutes:0,seconds:0,milliseconds:0})
				.getMonth() * dt1.getFullYear() - 
			dt2
				.duplicate()
				.set({days:1,hours:0,minutes:0,seconds:0,milliseconds:0})
				.getMonth() * dt2.getFullYear()
				)
			);
		}
		
	Date.prototype.getDaysDiffStr=function(dt1,dt2){
		var diff = getDaysDiff(dt1,dt2);
		switch(diff){
			case 0:
				return _( 'core:today' );
			case 1:
				return _( 'core:tomorrow' );
			case 2:
				return _( 'core:after_tomorrow' );
			case -1:
				return LT.text.dateYesterday;
			case -2:
				return LT.text.date2DaysAgo;
			default:
				if (diff>0){
					return _( 'core:after_days' , diff )
					}
				else{
					return j( Math.abs(diff), ' ' , LT.text.dateDaysBefore )
					}
			}
		}
		
	Date.prototype.duplicate=function(dt){
		if (dt){
			this.setTime(dt.getTime());
			return this;
			}
		else{
			return new Date(this.getTime());
			}
		}
	
	Date.prototype.format=function(template){
		var dt=this;
		return template.replace(/([a-zA-Z]{1})/g,function(w,g){
			switch (g){
				case 'H':
					return dt.getHours().setDigits()
					break;
				case 'i':
					return dt.getMinutes().setDigits()
					break;
				case 's':
					return dt.getSeconds().setDigits()
					break;
				case 'j':
					return dt.getDate()
					break;
				case 'd':
					return dt.getDate().setDigits()
					break;
				case 'm':
					return (dt.getMonth()+1).setDigits()
					break;
				case 'M':
					return MONTHS[dt.getMonth()]
					break;
				case 'n':
					return  String(MONTHS_SHORT[dt.getMonth()]).firstCharUpper()
					break;
				case 'F':
					return MONTHS_SHORT[dt.getMonth()]
					break;
				case 'G':
					return String(MONTHS_SHORT[dt.getMonth()]).firstCharUpper();
					break;
				case 'f':
					return MONTHS_NOMINATIVE[dt.getMonth()]
					break;
				case 'Y':
					return dt.getFullYear().setDigits()
					break;
				case 'y':
					return dt.getFullYear().toString().substr( -2)
					break;
				case 'r':
					return dt.getDaysDiffStr(dt,new Date())
					break;
				case 'e':
					return dt.getWeekday().toLowerCase()
					break;
				case 'w':
					return dt.getWeekReadable()
					break;
				case 'o':
					return dt.getMonthReadable()
					break;
				}
			});
		}
